如何跨模型共享代码? (Rails 2.3)

时间:2010-02-28 22:28:47

标签: ruby-on-rails

我有两种方法可以在模型之间共享,而不是复制和粘贴它们。在控制器中,我可以通过将方法放在application_controller.rb中来实现,该方法自动包含在每个控制器中。 模型有类似的东西吗?

谢谢!

5 个答案:

答案 0 :(得分:16)

您可以在Rails应用的functionality.rb目录中创建名为lib或类似内容的文件。使模块命名的文件在Rails启动时自动加载。例如,如果我想将标记添加到多个模型,我将创建一个名为lib/flagging.rb的文件,它看起来像这样:

module Flagging
  # Flags an object for further review
  def flag!
    self.update_attribute(:flagged, true)
  end

  # Clears all flags on an object
  def deflag!
    self.update_attribute(:flagged, false)
  end
end

在我希望添加此功能的每个模型中,我都会执行以下操作:

class Foo < ActiveRecord::Base
  include Flagging
end

然后我可以做类似的事情:

foo = Foo.create
foo.flag!

答案 1 :(得分:4)

上面的顶级解决方案对我有用。在Rails 3中,我发现我还必须使用:config.autoload_paths += Dir["#{config.root}/lib/**/"]更新application.rb文件,如下所示:Best way to load module/class from lib folder in Rails 3?

答案 2 :(得分:3)

你可以a)做一些类似于application_controller的事情,并创建一个模型类,其他人可以从中继承或b)使用模块。

答案 3 :(得分:2)

您可以通过多种方式在两个模型类之间共享方法。

  • 如果模型彼此相关,请使用inheritance,例如包含方法的共享父类,或者包含方法的另一个子类。
  • 使用可在多个模型之间共享的modules/mixins

答案 4 :(得分:0)

要添加Josh的答案,有时您可能想要共享一些定义多态关联的代码。您不能只在模块中放置has_many方法调用,因为您将收到错误,例如在名为Votable的模块中:

undefined method `has_many' for Voteable:Module (NoMethodError)

相反,您需要使用self.included(base)方法和base.instance_eval。以下是我的Voteable模块的示例:

module Voteable

  def self.included(base)
    base.instance_eval do
      has_many :votes, as: :voteable
      has_many :voters, through: :votes
    end
  end

  def voted_up_by?(user)
    user and votes.exists?(value: 1, voter_id: user)
  end

  def voted_down_by?(user)
    user and votes.exists?(value: -1, voter_id: user)
  end

end

现在,您可以在具有该行为的模型中include Voteable。这将执行self.included(base)方法,它将定义包含类的关联。