What's wrong with that? Yes, I could make an if else statement, but I wanna do that with case statements.
In my Controller
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
# is always ELSE when I do this:
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
Model User
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
The way case
works is it doesn't call whatever method you wanted to put in the when
clause. Instead it uses ===
on the when
clause passing the case
-ed thingy as argument.
In other words:
case user
when admin? then 42
end
Isn't
42 if user.admin?
But
42 if admin? === user
And as you don't have an admin?
method in the controller, you get a NoMethodError
.
Just rewrite it with simple if
- elsif
instead.
ndn explained already in his answer why the case statement in your example is not working.
You can switch to an if/elsif
block or a slightly longer when current_user.admin?
syntax. Or you can define some methods returning lambdas:
def is_admin?
->(user) { user.is_admin? }
end
def has_role?(role)
->(user) { user.has_role?(role) }
end
With these you can write:
query_limit = case current_user
when nil then 5
when is_admin? then 200
when has_role?('registered') then 20
else 5
end
You could write it this way, which is basically a disguised 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
According to the Ruby documentation:
Case statements consist of an optional condition, which is in the position of an argument to case, and zero or more when clauses. The first when clause to match the condition (or to evaluate to Boolean truth, if the condition is null) “wins”, and its code stanza is executed.
If you specify current_user
as the case condition, then the first when
expression that matches current_user
will be executed. current_user.is_admin?
returns a boolean value which will never be equal to current_user
, so your second example will always take the else
branch:
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
Your first example is broken because there is no local is_admin?
method defined. case
does not know to call is_admin?
on current_user
in this case.
To fix your code, you can remove case condition. In this case the first when
clause that evaluates to a truthy value will be chosen:
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
A case statement works by comparing the given value against the values of the when
statements (using ===
). So case current_user; when current_user.is_admin?
case current_user; when current_user.is_admin?
checks whether current_user
is equal to current_user.is_admin?
, which it's obviously not going to be.
Basically
case x
when y
case1
when z
case2
...
end
is equivalent to
if y === x
case1
elsif z === x
case2
...
end
If that structure does not fit your use case, you should use case
.
PS: return
returns from the current method, so it's not what you want here.
PPS: You can also use case
without an expression as a different way to write an arbitrary if-elsif chain. So you could do what you want like this:
query_limit = case
when current_user == nil
5
when current_user.is_admin?
200
...
end
But of course you can also just use a plain if-elsif for this. It's really just a matter of preference.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.