在哪里放置在多个模型中找到的通用代码?

发布于 2024-08-09 23:02:59 字数 484 浏览 4 评论 0原文

我有两个包含相同方法的模型:

def foo
  # do something
end

我应该把它放在哪里?

我知道公共代码位于 Rails 应用程序的 lib 目录 中。

但是,如果我将其放入 lib 中名为“Foo”的新类中,并且我需要将其功能添加到我的两个 ActiveRecord 模型 ,我是否这样做:

class A < ActiveRecord::Base
includes Foo

class B < ActiveRecord::Base
includes Foo

然后 AB 都将包含 foo 方法,就像我在每个方法中定义了它一样?

I have two models that contain the same method:

def foo
  # do something
end

Where should I put this?

I know common code goes in the lib directory in a Rails app.

But if I put it in a new class in lib called 'Foo', and I need to add its functionality to both of my ActiveRecord models, do I do that like this:

class A < ActiveRecord::Base
includes Foo

class B < ActiveRecord::Base
includes Foo

and then both A and B will contain the foo method just as if I had defined it in each?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

静谧 2024-08-16 23:02:59

创建一个模块,您可以将其放入 lib 目录中:

module Foo
  def foo
    # do something
  end
end

然后您可以在每个模型类中包含该模块:

class A < ActiveRecord::Base
  include Foo
end

class B < ActiveRecord::Base
  include Foo
end

AB 模型现在将定义一个 foo 方法。

如果您遵循 Rails 命名约定,使用模块名称和文件名称(例如 foo.rb 中的 Foo 和 foo_bar.rb 中的 FooBar),那么 Rails 将自动为您加载该文件。否则,您将需要使用 require_dependency 'file_name' 加载您的 lib 文件。

Create a module, which you can put in the lib directory:

module Foo
  def foo
    # do something
  end
end

You can then include the module in each of your model classes:

class A < ActiveRecord::Base
  include Foo
end

class B < ActiveRecord::Base
  include Foo
end

The A and B models will now have a foo method defined.

If you follow Rails naming conventions with the name of the module and the name of the file (e.g. Foo in foo.rb and FooBar in foo_bar.rb), then Rails will automatically load the file for you. Otherwise, you will need to use require_dependency 'file_name' to load your lib file.

江心雾 2024-08-16 23:02:59

您实际上有两个选择:

  1. 使用通用逻辑模块并将其包含在 A & 中。 B
  2. 使用扩展 ActiveRecord 并具有 A 和 A 的通用类 C; B 扩展 C。

如果共享功能不是每个类的核心,但适用于每个类,则使用#1。例如:

(app/lib/serializable.rb)
module Serializable
  def serialize
    # do something to serialize this object
  end
end

如果共享功能对于每个类和 A 和 A 都是通用的,则使用#2。 B 具有天然的关系:

(app/models/letter.rb)
class Letter < ActiveRecord::Base
  def cyrilic_equivilent
    # return somethign similar
  end
end

class A < Letter
end

class B < Letter
end

You really have two choices:

  1. Use a module for common logic and include it in A & B
  2. Use a common class C that extends ActiveRecord and have A & B extend C.

Use #1 if the shared functionality is not core to each class, but applicable to each class. For example:

(app/lib/serializable.rb)
module Serializable
  def serialize
    # do something to serialize this object
  end
end

Use #2 if the shared functionality is common to each class and A & B share a natural relationship:

(app/models/letter.rb)
class Letter < ActiveRecord::Base
  def cyrilic_equivilent
    # return somethign similar
  end
end

class A < Letter
end

class B < Letter
end
倾`听者〃 2024-08-16 23:02:59

我是这样做的...首先创建 mixin:

module Slugged
  extend ActiveSupport::Concern

  included do
    has_many :slugs, :as => :target
    has_one :slug, :as => :target, :order => :created_at
  end
end

然后将其混合到需要它的每个模型中:

class Sector < ActiveRecord::Base
  include Slugged

  validates_uniqueness_of :name
  etc
end

这几乎很漂亮!

为了完成这个例子,虽然它与问题无关,但这是我的 slug 模型:

class Slug < ActiveRecord::Base
  belongs_to :target, :polymorphic => true
end

Here's how I did it... First create the mixin:

module Slugged
  extend ActiveSupport::Concern

  included do
    has_many :slugs, :as => :target
    has_one :slug, :as => :target, :order => :created_at
  end
end

Then mix it into every model that needs it:

class Sector < ActiveRecord::Base
  include Slugged

  validates_uniqueness_of :name
  etc
end

It's almost pretty!

To complete the example, though it's irrelevant to the question, here's my slug model:

class Slug < ActiveRecord::Base
  belongs_to :target, :polymorphic => true
end
半边脸i 2024-08-16 23:02:59

一种选择是将它们放在新目录中,例如 app/models/modules/。然后,您可以将其添加到 config/environment.rb 中:

Dir["#{RAILS_ROOT}/app/models/modules/*.rb"].each do |filename|
  require filename
end

这将需要该目录中的每个文件,因此如果您将如下所示的文件放入模块目录中:

module SharedMethods
  def foo
    #...
  end
end

然后你就可以在你的模型中使用它,因为它会自动加载:

class User < ActiveRecord::Base
  include SharedMethods
end

这种方法比将这些 mixins 放在 lib 目录中更有组织性,因为它们位于使用它们的类附近。

One option is to put them in a new directory, for example app/models/modules/. Then, you can add this to config/environment.rb:

Dir["#{RAILS_ROOT}/app/models/modules/*.rb"].each do |filename|
  require filename
end

This will require every file in in that directory, so if you put a file like the following in your modules directory:

module SharedMethods
  def foo
    #...
  end
end

Then you can just use it in your models because it will be automatically loaded:

class User < ActiveRecord::Base
  include SharedMethods
end

This approach is more organized than putting these mixins in the lib directory because they stay near the classes that use them.

谷夏 2024-08-16 23:02:59

如果您需要 ActiveRecord::Base 代码作为常用功能的一部分,那么使用抽象类也可能很有用。比如:

class Foo < ActiveRecord::Base
  self.abstract_class = true
  #Here ActiveRecord specific code, for example establish_connection to a different DB.
end

class A < Foo; end
class B < Foo; end

就这么简单。另外,如果代码与 ActiveRecord 无关,请查找 ActiveSupport::Concerns 作为更好的方法。

If you need ActiveRecord::Base code as a part of your common functionalities, using an abstract class could be useful too. Something like:

class Foo < ActiveRecord::Base
  self.abstract_class = true
  #Here ActiveRecord specific code, for example establish_connection to a different DB.
end

class A < Foo; end
class B < Foo; end

As simple as that. Also, if the code is not ActiveRecord related, please find ActiveSupport::Concerns as a better approach.

怕倦 2024-08-16 23:02:59

正如其他人提到的, include Foo 是做事的方式......但是,它似乎无法通过基本模块为您提供所需的功能。以下是许多 Rails 插件除了新实例方法之外添加类方法和新回调的形式。

module Foo #:nodoc:

  def self.included(base) # :nodoc:
    base.extend ClassMethods
  end

  module ClassMethods
    include Foo::InstanceMethods

    before_create :before_method
  end

  module InstanceMethods
    def foo
      ...
    end

    def before_method
      ...
    end
  end 

end

As others have mentioned include Foo is the way to do things... However it doesn't seem to get you the functionality you want with a basic module. The following is the form a lot of Rails plugins take to add class methods and new callbacks in addition to new instance methods.

module Foo #:nodoc:

  def self.included(base) # :nodoc:
    base.extend ClassMethods
  end

  module ClassMethods
    include Foo::InstanceMethods

    before_create :before_method
  end

  module InstanceMethods
    def foo
      ...
    end

    def before_method
      ...
    end
  end 

end
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文