是否有一个Rails宏来动态地向模型中添加许多类似的方法?

时间:2012-05-16 13:34:33

标签: ruby ruby-on-rails-3 dynamic metaprogramming

我觉得我在某处读到了一个动态生成模型上许多类似实例方法的ActiveRecord宏,但现在(尽管通过在线文档和RoR书籍查看)我找不到它。

我使用普通的Ruby解决了这个问题,但如果有更好的(更多Rails-y)方法,我想知道它。

所以,我有CharacterGearModifiers模型(是的,这是RPG的应用)。角色将拥有Gear,为他的统计数据添加修饰符。所以我想要一个方法来查询他的装备(和他的装备的修改器)的每个属性,并总结相关统计数据的修饰符。 (参见下面代码中的方法)。

所以我的角色模型如下所示:

class Character < ActiveRecord::Base
  has_many :gears
  has_many :modifiers, :as => :modifiable, :through => :gears

  stats = ["hp", "bab", "ac"]  # etc...


  stats.each do |method_name|
    define_method method_name do 
      self.modifiers.where(:kind => method_name).sum(:amount)  
    end    
  end

end

所以,这样我可以做到

>  jim = Character.create(:name => "Jim")

然后给吉姆一些修改他的“hp”,“bab”或“ac”的装备然后我就可以这样做:

>  jim.hp

>  jim.ac

等...

2 个答案:

答案 0 :(得分:2)

这不是更多(Rails-y)方式,但它是代码的替代方案。方法缺失。

rubylearning.com对此有何评论。

当您向对象发送消息时,该对象将执行它在方法查找路径中找到的第一个方法,该方法的名称与消息的名称相同。如果找不到任何此类方法,则会引发NoMethodError异常 - 除非您为该对象提供了一个名为method_missing的方法...

def method_missing(m, *args, &block)  
  self.modifiers.where(:kind => method_name).sum(:amount)    
end

关于这种方法的优点是你不需要维护你的stats数组并通过它们循环来为每个stat定义一个方法。缺点是如果每次有一个用户的missing_method它就会执行此代码,这可能是危险的。

答案 1 :(得分:0)

你可能正在考虑ActiveRecord::Base.store,它出现在Rails 3.2中。有了它,你可以这样做:

class Character < ActiveRecord::Base
  store :stats, accessors: [:hp, :bab, :ac]
end
 
jim = Character.create(:name => "Jim")
jim.hp = 100

注意:stats列应定义为text列,以确保您有足够的空间容纳您的值。

Read more in the Rails docs