Использование структур в Ruby on Rails дает динамическое постоянное назначение (SyntaxError)
В моем контроллере у меня есть следующий упрощенный код:
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
Но Ruby дает следующую ошибку:
динамическое назначение констант (SyntaxError)
в строке, указанной выше.
Что, AFAIK, означает, что константа DashItem
уже определена. Это верно? И что с этим делать?
Ответы
Ответ 1
Ошибка объясняет, в чем проблема: у вас есть константа, назначенная в слишком динамичном контексте, то есть внутри метода индекса.
Решение состоит в том, чтобы определить его снаружи:
DashItem = Struct.new(:name, :amount, :moderated)
def index
@dashboard_items = []
...
Ответ 2
Если вы хотите аккуратно держать все в своем методе индекса, вы можете сделать это:
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
Как сказал gunn, вы просто не можете явно назначать константу внутри такого метода...
Это решение больше объясняется в документах ruby здесь, второй пример на странице.
Ответ 3
И если (при определенных обстоятельствах) вы начнете получать warning: redefining constant Struct…
при использовании ответа Lexun добавление условного unless Struct::const_defined? 'DashItem'
unless Struct::const_defined? 'DashItem'
может помочь.
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
Конечно, важно помнить, что указанное предупреждение может быть действительным, и вы можете переопределять то, что вы на самом деле не хотите переопределять. Поэтому убедитесь, что вы знаете, что делаете, прежде чем использовать вышеуказанный способ, чтобы заставить замолчать предупреждение (и обойти переопределение).