Using structs in Ruby on Rails gives dynamic constant assignment (SyntaxError)
In my controller I have the following simplified code:
def index
@dashboard_items = []
DashItem = Struct.new(:name, :amount, :moderated) # Error is here
[:page, :post].each do |c|
obj = c.to_s.capitalize.constantize
@dashboard_items << DashItem.new(c.to_s, obj.count, obj.count_moderated)
end
end
But Ruby gives the following error:
dynamic constant assig开发者_StackOverflownment (SyntaxError)
on the line marked above.
Which, AFAIK, means that the constant DashItem
is already defined. Is this correct? And what to do about it?
The error explains what the problem is - you have a constant being assigned in a context that's too dynamic - i.e. inside the index method.
The solution is to define it outside:
DashItem = Struct.new(:name, :amount, :moderated)
def index
@dashboard_items = []
...
If you want to keep the whole thing neatly inside your index method you could do this:
def index
@dashboard_items = []
# Set the name of your struct class as the first argument
Struct.new('DashItem', :name, :amount, :moderated)
...
# Then when you want to create an instance of your structure
# you can access your class within the Struct class
@dashboard_items << Struct::DashItem.new(c.to_s, obj.count, obj.moderated)
end
As gunn said, you just can't explicitly assign a constant within a method like that...
This solution is explained more in the ruby docs here, second example on the page.
Another simple option here would be to use a local var instead of a constant when assigning and instantiating the Struct in a dynamic setting:
def index
# ...
dash_item = Struct.new(:name, :amount, :moderated)
# ...
@dashboard_items << dash_item.new( ... )
# ...
end
And if (under circumstances) you start getting warning: redefining constant Struct…
when using Lexun's answer then adding a conditional unless Struct::const_defined? 'DashItem'
can help.
def index
@dashboard_items = []
# Set the name of your struct class as the first argument
Struct.new('DashItem', :name, :amount, :moderated) unless Struct::const_defined? 'DashItem'
...
# Then when you want to create an instance of your structure
# you can access your class within the Struct class
@dashboard_items << Struct::DashItem.new(c.to_s, obj.count, obj.moderated)
end
Of course it's important to remember that said warning may be valid and you might be redefining something you don't actually want to redefine. So make sure you know what you're doing before using the above way to silence the warning (and bypass redefining).
精彩评论