【问题标题】:Why is my ruby case statement not working?为什么我的 ruby​​ 案例语句不起作用?
【发布时间】:2023-03-06 09:26:01
【问题描述】:

这有什么问题? 是的,我可以做一个 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

【问题讨论】:

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


    【解决方案1】:

    根据 Ruby 文档:

    Case 语句由一个可选条件(位于 case 参数的位置)和零个或多个 when 子句组成。匹配条件的第一个 when 子句(如果条件为空,则计算为布尔真值)“获胜”,并执行其代码节。

    如果您指定current_user 作为case 条件,那么第一个匹配current_userwhen 表达式将被执行。 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?

    要修复您的代码,您可以删除大小写条件。在这种情况下,将选择第一个评估为真值的 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
    

    【讨论】:

    • when nil 没有case 的任何参数?
    • 哎呀,我的错。固定。
    • 现在它已经修复了,你的代码和我的答案完全相同。
    • 这帮助我为我的模型方法编写案例...when 语句。我的条件需要使用self,我很困惑如何将它与 case...when 结合起来。这个答案帮助我意识到我不需要在案例声明中使用声明。我可以像“if”一样使用“when”。这样就容易多了。谢谢!
    【解决方案2】:

    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 重写即可。

    【讨论】:

      【解决方案3】:

      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
      

      【讨论】:

        【解决方案4】:

        你可以这样写,基本上是伪装的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
        

        【讨论】:

          【解决方案5】:

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2021-10-10
            • 2011-07-16
            • 2012-07-21
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-12-20
            • 2013-09-30
            相关资源
            最近更新 更多