在运行时动态地将模块包含到模型中?

时间:2012-07-06 20:29:24

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

我有一个“事务”(扩展了ActiveRecord :: Base)。我有两种不同类型的交易,即“购买”或“捐赠”。两者之间有足够的重叠,因此不需要创建两个单独的数据库表,因此我只有一个表用于具有“item_type”列的事务。

但是,购买和捐赠有不同的方法和验证,因此将它们分成两个不同的控制器和模型是有意义的。我没有创建ActiveBase模型(减去表格),而是试图为每个模型使用模块。

以下是Purchase模块的外观。

module Purchase
  def self.included(base)
    base.validates :amount, 
      :presence => true
  end

  def testing
    "testing"
  end
end

以下是创建一个的方法:(此代码位于Purchases控制器的create操作中)

@purchase = Transaction.new(params[:purchase]).extend(Purchase)

我可以打电话给@ purchase.testing并返回“测试”。但是,验证没有运行。

如果我在交易模型上以传统方式包含模块,使用“包含购买”,那么它们就可以工作。

我是如何实现这个工作流程的?我跟着这一点:http://paulsturgess.co.uk/articles/84-how-to-include-class-and-validation-methods-using-a-module-in-ruby-on-rails

2 个答案:

答案 0 :(得分:5)

如果您只想使用单个表和多个列,我认为首选方法是单表继承。如果搜索单表继承,可以阅读它here。但是,关于如何包含模块的问题,我认为您希望将模块包含在@purchase的元类中,因此它不包含在所有后续事务中。有点像这样(绝对可以缩短):

@purchase = Transaction.new(params[:purchase])
class << @purchase
  include Purchase
end

然后,您的验证应该有效。

答案 1 :(得分:3)

执行included时,您的.extend(Purchase)挂钩将无法运行。你需要一个extended钩子。在extended钩子内部,您可以在新Transaction对象的本征类上调用Rails验证助手(类似于@Adam演示的那样)。