如何在不同模型之间共享代码?(Rails 2.3)

13

我有一些方法想要在模型之间共享,而不是复制和粘贴它们。在控制器中,我可以通过将这些方法放在application_controller.rb文件中来实现,这样每个控制器都会自动包含这些方法。 那么对于模型,是否有类似的方法呢?

谢谢!

5个回答

16

你可以在Rails应用程序的lib目录中创建一个名为functionality.rb或类似名称的文件。将文件命名为模块名称,以便在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
老兄,关键在于lib目录。我已经开始把更多的代码放在那里了,这就是一个很方便的组织代码的地方。 - JP Silvashy

4

3

您可以选择a)类似于application_controller的方式,创建一个模型类,然后其他模块可以继承它,或者b)使用模块。


2

有许多方法可以在两个模型类之间共享方法。

  • 如果这些模型彼此相关,例如包含方法的共享父类或一个子类继承了另一个子类并包含方法,则可以使用继承
  • 使用模块/混合,可以在多个模型之间共享。

将这些方法转变为帮助方法,使得两个模型都可以访问 - 我以为模型无法访问帮助方法。这是如何实现的呢?(似乎对于我想要做的事情来说是最干净的方法) - Yuval Karmi
你说得对。我原本在考虑实用方法,而不是 Rails 中的“辅助方法”。因此,混合方法的方法比实用方法更有用。 - marklai

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

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

在Rails 3中,这变得更加容易了 - 您可以使用extend ActiveSupport :: Concern included替换def self.included(base)base.instance_eval - Joshua Coady

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接