如何重构此案例陈述?

时间:2013-03-15 08:05:12

标签: ruby-on-rails ruby-on-rails-3 cancan

所以我想做的是根据current_user的角色进行重定向。

这就是我所拥有的:

  path = case current_user.roles.where(:name => "vendor")
    when :vendor
      dashboard_path
    when :guest
      home_path
    else
      home_path
  end

  redirect_to path     

我正在使用cancan,我知道的唯一方法是找出用户的角色,要么current_user.has_role? :admin还是current_user.roles.where(:name => role_name)

鉴于这些限制(或告诉我另一种方法来确定用户的角色),我如何让这个案例陈述起作用?

修改1

假设我正在检查多个角色,而不仅仅是我在这里的2个角色 - 可能是4个或5个。

修改2

要清楚,这是我目前的设置。

我正在使用Devise,CanCan& Rolify。 Rolify允许用户拥有多个角色,但我的应用程序不具备该用例。用户只有一个角色。它们可以是vendor, buyer, guest, superadmin

如果他们是vendor,他们只能看到属于他们的dashboard_path。他们看不到任何属于其他任何人的vendor storefront。他们也不应该看到其他供应商的产品。因此,一旦他们登录,他们的root_path应该是dashboard_path而不是home_path,这就是每个其他角色的root_path

如果他们是guest,他们可以看到除价格之外的所有东西 - 我已经有了这个逻辑。我这样做了:

if user.has_role? :guest
    can :read, [Product, Vendor, Banner]
    cannot :view_prices, Product
end

然后在我看来,我刚做了类似的事情:

<% if can? :view_prices, Product %>
    <div class="price pull-right">
      <%= number_to_currency(@product.price) %> ea
    </div>      
<% else %>
   <span class="no-price pull-right"><%= link_to "Log In To See Price", login_path %></span>
<% end %>

所以,基本上......我的真正目标是根据用户的角色尝试更改root_path。我基本上试图在this question上实现答案。

2 个答案:

答案 0 :(得分:6)

最终答案 (适用于早期的导师,见下文)

如果您的用户只能拥有一个角色,我会说您当前的实施并不完全合适。但是,如果您确实需要保留此实现,则可以执行以下操作:

class User < ActiveRecord::Base
  # this will return the name of the first (so the only one) 
  # role that your user has, or nil. 
  def role_name
    roles.first.try( :name ) 
  end
end  

所以现在你的案例陈述会起作用:

path = case current_user.role_name
         when 'vendor' ; dashboard_path
         when 'guest'  ; home_path
         when 'foo'    ; bar_path
         else home_path
       end

我仍然鼓励您将案例陈述包装在帮助程序中,以便重用并更容易维护。

更早的回答

我不确定我理解你的问题,但我认为你不需要这里的案例陈述:

redirect_to (current_user.has_role? :vendor ? dashboard_path : home_path)

另一种方法是将部分责任推送到用户类(或演示者):

class User < ActiveRecord::Base
  def home_page
    # here some logic to return a symbol like :home or :dashboard,
    # depending on your roles implementation. Your User could even use
    # a state machine to do this, or have multiple decorators.
  end
end

然后带帮助者

 def home_path_for( user )
   case user.home_page
     when :home      ; home_path
     when :dashboard ; dashboard_path
     when :foo       ; bar_path
     else home_path
   end
 end

第一次编辑

如果您的用户一次可以拥有多个角色,我会说案例陈述不合适。 case是一个分支声明,仅当您在一组可能的结果中只有一个且只有一个输入一个且只有一个结果时才适用。

因此,您必须将角色列表减少到中间状态,例如:

 DASHBOARD_ROLES = [:vendor, :admin]
 CLIENT_ROLES    = [:client, :prospect]
 BASIC_ROLES     = [:logged_visitor]

 if (DASHBOARD_ROLES & user_roles).any?
   :admin_dashboard
 else if (CLIENT_ROLES & user_roles).any?
   :client_dashboard
 # additionnal, different logic is possible
 else if (BASIC_ROLES & user_roles).any? && user_logged_in? && user_roles.first != :prospect
   :logged_dashboard
 else
   :home
 end

这是一种完全不同的逻辑。

答案 1 :(得分:1)

首先,如果可能,您可能需要解决用户具有多个角色的情况。

假设用户有一个角色(虽然我们可以根据需要添加更多条件)你能考虑一个哈希吗?

像 -

path = {:vendor => dashboard_path, :guest => home_path} [current_user.active_role] || default_path

我做了一些假设 -

  1. current_user.active_role可以是用户的当前角色,您可以根据该角色重定向答案。
  2. default_path是不言自明的。