27

同じメソッドを含む 2 つのモデルがあります。

def foo
  # do something
end

これはどこに置けばいいですか?

一般的なコードがRails アプリのlibディレクトリにあることは知っています。

libしかし、それを' ' という名前の新しいクラスに入れ、Fooその機能を my の両方に追加する必要がある場合、次のActiveRecord modelsようにしますか?

class A < ActiveRecord::Base
includes Foo

class B < ActiveRecord::Base
includes Foo

と の両方Aでメソッドを定義したかのようにメソッドBが含まれますか?foo

4

6 に答える 6

39

libディレクトリに配置できるモジュールを作成します。

module Foo
  def foo
    # do something
  end
end

次にinclude、各モデル クラスでモジュールを使用できます。

class A < ActiveRecord::Base
  include Foo
end

class B < ActiveRecord::Base
  include Foo
end

AモデルとBモデルにメソッドがfoo定義されます。

モジュールの名前とファイルの名前で Rails の命名規則に従う場合 (たとえば、foo.rb では Foo、foo_bar.rb では FooBar)、Rails は自動的にファイルをロードします。require_dependency 'file_name'それ以外の場合は、 lib ファイルをロードするために を使用する必要があります。

于 2009-11-08T23:29:41.773 に答える
14

実際には次の 2 つの選択肢があります。

  1. 共通ロジックのモジュールを使用し、A & B に含める
  2. ActiveRecord を拡張する共通クラス C を使用し、A と B が C を拡張するようにします。

共有機能が各クラスのコアではなく、各クラスに適用できる場合は #1 を使用します。例えば:

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

共有機能が各クラスに共通で、A と B が自然な関係を共有している場合は、#2 を使用します。

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

class A < Letter
end

class B < Letter
end
于 2009-11-09T00:24:01.703 に答える
6

これが私がやった方法です...最初にミックスインを作成します:

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

それはほとんどきれいです!

例を完成させるために、質問とは関係ありませんが、ここに私のスラッグモデルがあります:

class Slug < ActiveRecord::Base
  belongs_to :target, :polymorphic => true
end
于 2013-02-07T02:08:26.187 に答える
5

共通機能の一部として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、より良いアプローチとして見つけてください。

于 2013-12-23T19:23:17.770 に答える
5

1 つのオプションは、たとえば、新しいディレクトリに配置することですapp/models/modules/。次に、これをに追加できますconfig/environment.rb

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

これによりrequire、そのディレクトリ内のすべてのファイルが削除されるため、モジュールディレクトリに次のようなファイルを配置すると:

module SharedMethods
  def foo
    #...
  end
end

その後、自動的にロードされるため、モデルで使用できます。

class User < ActiveRecord::Base
  include SharedMethods
end

libこのアプローチは、これらの mixinを使用するクラスの近くにとどまるため、これらの mixin をディレクトリに配置するよりも整理されています。

于 2009-11-08T23:36:06.163 に答える
4

他の人が言及しているように、 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
于 2009-11-09T18:19:22.070 に答える