为什么我的ruby案例陈述不起作用?

时间:2017-07-08 12:01:41

标签: ruby-on-rails ruby switch-statement case

这有什么问题? 是的,我可以做一个if else声明,但我想用case语句做。

在我的控制器中

query_limit = case current_user
                when nil
                  return 5
                when is_admin?
                  return 200
                when has_role?('registered')
                  return 20
                else
                  return 5
              end


NoMethodError (undefined method `is_admin?' for #<V1::MyController:123123123>):
当我这样做时,

puts query_limit#总是ELSE:

 query_limit = case current_user
                    when nil
                      return 5
                    when current_user.is_admin?
                      return 200
                    when current_user.has_role?('registered')
                      return 20
                    else
                      return 5
                  end

模型用户

class User
  def is_admin?
    self.has_role?('administrator')
  end

  def has_role?(the_role)
    self.roles.any? {|role| role.slug == the_role}
  end
end

5 个答案:

答案 0 :(得分:5)

case的工作方式是它不会调用您想要放在when子句中的任何方法。相反,它在===子句上使用when,将case - ed thingy作为参数传递。

换句话说:

case user
when admin? then 42
end

42 if user.admin?

但是

42 if admin? === user

由于您在控制器中没有admin?方法,因此获得NoMethodError

只需用简单的if - elsif重写即可。

答案 1 :(得分:4)

ndn在他的回答中解释了为什么你的例子中的case语句不起作用。

您可以切换为if/elsif块或稍长when current_user.admin?的语法。或者你可以定义一些返回lambdas的方法:

def is_admin?
  ->(user) { user.is_admin? }
end

def has_role?(role)
  ->(user) { user.has_role?(role) }
end

有了这些,你可以写:

query_limit = case current_user
              when nil then 5
              when is_admin? then 200
              when has_role?('registered') then 20
              else 5
              end

答案 2 :(得分:1)

你可以这样写,这基本上是一个伪装的if/elsif

query_limit = case
                when current_user.nil?
                  return 5
                when current_user.is_admin?
                  return 200
                when current_user.has_role?('registered')
                  return 20
                else
                  return 5
                end

答案 3 :(得分:1)

根据Ruby文档:

  

Case语句由一个可选条件组成,该条件位于case的参数位置,并且在子句时为零或更多。匹配条件的第一个when子句(或者如果条件为null则求值为布尔值,则为“wins”,并执行其代码节。

如果指定current_user作为案例条件,则将执行与when匹配的第一个current_user表达式。 current_user.is_admin?返回一个永远不等于current_user的布尔值,因此您的第二个示例将始终采用else分支:

case current_user
  when nil  # current_user != nil, skip condition
    return 5
  when current_user.is_admin?  # current_user != current_user.is_admin?, skip condition
    return 200
  when current_user.has_role?('registered')  # and so on
    return 20
  else
    return 5
end

您的第一个示例已损坏,因为未定义本地is_admin?方法。在这种情况下,case无法在is_admin?上致电current_user

要修复代码,您可以删除案例条件。在这种情况下,将选择评估为真值的第一个when子句:

case  # no current_user here!
  when current_user.nil?  # current_user.nil? is false, skip condition
    return 5
  when current_user.is_admin?  # current_user.is_admin? is truthy, run this one!
    return 200
  when current_user.has_role?('registered')
    return 20
  else
    return 5
end

答案 4 :(得分:1)

case语句的工作原理是将给定值与when语句的值进行比较(使用===)。因此case current_user; when current_user.is_admin?会检查current_user是否等于current_user.is_admin?,这显然不是。{/ p>

基本上

case x
  when y
    case1
  when z
    case2
  ...
end

相当于

if y === x
  case1
elsif z === x
  case2
...
end

如果该结构不适合您的使用案例,则应使用case

PS:return从当前方法返回,所以这不是你想要的。

PPS:您也可以在没有表达式的情况下使用case作为编写任意if-elsif链的不同方式。所以你可以这样做你想做的事情:

query_limit = case
  when current_user == nil
    5
  when current_user.is_admin?
    200
  ...
end

但是当然你也可以使用普通的if-elsif。这只是一个偏好问题。