2017-07-08 132 views
0

这是什么问题? 是的,我可以做一个if else语句,但我想用case语句做这件事。为什么我的ruby 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 

回答

-1

按照Ruby文档:

Case语句包括一个可选的条件,这是在位置的情况下的争论,以及当条款时零或更多。第一个when子句匹配条件(或者评估为布尔真值,如果条件为空)“胜出”,并且其代码段被执行。

如果指定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不知道在current_user上致电is_admin?

要修复您的代码,您可以移除案例条件。在这种情况下,计算结果为truthy值第一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 
+1

'当nil'没有为'case'任何说法? –

+0

哎呀,我的坏。固定。 –

+1

现在它已修复,您的代码与我的答案完全相同。 –

4

的方式case作品是它不调用无论您想在when中输入什么方法条款。相反,它使用when子句中的===,通过case作为参数。

换句话说:

case user 
when admin? then 42 
end 

是不是

42 if user.admin? 

42 if admin? === user 

而当你没有在控制器的admin?方法,你会得到一个NoMethodErrorelsif代替 -


简单if就重写。

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 
1

case语句的工作方式(使用===)比较反对when语句的值给定值。所以case current_user; when current_user.is_admin?检查current_user是否等于current_user.is_admin?,这显然不会。

基本上

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这一点。这只是一个偏好问题。

3

ndn在他的回答中已经解释了为什么您的示例中的case语句不起作用。

您可以切换到if/elsif块或稍长的when current_user.admin?语法。或者,你可以定义一些方法返回lambda表达式:

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