问题
I'm a Python developer and I just started learning Rails, so this might be a noobish question. I found some surprising behavior in my code:
<!-- render flash message array if set -->
<% if flash[:notice].is_a? Array && !flash[:notice].empty? %>
This results in the following error: undefined method `empty?' for nil:NilClass
It seems like Ruby should not be calling .empty?
in the second part of this clause. I confirmed that short-circuit evaluation works in other cases:
# this is more what I expected
[3] pry(main)> a = nil
=> nil
[5] pry(main)> !a.nil? && a.empty?
=> false
...
[6] pry(main)> a = 1
=> 1
[7] pry(main)> !a.nil? && a.empty?
NoMethodError: undefined method `empty?' for 1:Integer
from (pry):7:in `__pry__'
Anyone know why this behavior is happening? Seems to only trigger when I use is_a?
and not the other operators.
回答1:
This is happening because you are using space and not brackets for the parameters of is_a?
function so rails is trying to send the whole thing as a parameter. Try it like this
<% if flash[:notice].is_a?(Array) && !flash[:notice].empty? %>
Explanation:
when you write flash[:notice].is_a? Array && !flash[:notice].empty?
rails interpret it like flash[:notice].is_a?(Array && !flash[:notice].empty?)
so Array
is evaluated as true
and !flash[:notice].empty?
is evaluated which raises the exception.
回答2:
It's because NilClass
does not respond to empty
:
nil.class #=> NilClass
nil.respond_to? :empty?
#=> false
While it responds to is_a?
:
nil.respond_to? :is_a?
#=> true
Shows all methods nil
respond to:
nil.methods
#=> [:&, :inspect, :to_a, :to_s, :===, :to_f, :to_i, :=~, :to_h, :nil?, :to_r, :rationalize, :|, :to_c, :^, :instance_variable_defined?, :remove_instance_variable, :instance_of?, :kind_of?, :is_a?, :tap, :instance_variable_set, :protected_methods, :instance_variables, :instance_variable_get, :public_methods, :private_methods, :method, :public_method, :public_send, :singleton_method, :define_singleton_method, :extend, :to_enum, :enum_for, :<=>, :!~, :eql?, :respond_to?, :freeze, :object_id, :send, :display, :hash, :class, :singleton_class, :clone, :dup, :itself, :yield_self, :then, :taint, :tainted?, :untaint, :untrust, :untrusted?, :trust, :frozen?, :methods, :singleton_methods, :equal?, :!, :==, :instance_exec, :!=, :instance_eval, :__id__, :__send__]
If you fix by checking first the existence of the value for the key
:notice
, as this example shows: https://api.rubyonrails.org/classes/ActionDispatch/Flash.html, a syntax error is raised, which points to the parenthesis missing:
flash[:notice] && flash[:notice].is_a? Array && flash[:notice].empty?
# syntax error, unexpected tCONSTANT, expecting end-of-input
# ...] && flash[:notice].is_a? Array && flash[:notice].empty?
# ^~~~~
来源:https://stackoverflow.com/questions/58052202/why-does-a-is-a-array-a-empty-raise-nomethoderror