web-dev-qa-db-ja.com

Rails ActiveRecord :: Baseの拡張

ActiveRecord:Baseクラスを拡張して、モデルにいくつかの特別なメソッドを追加する方法について、いくつか読んでいます。それを拡張する簡単な方法は何ですか(ステップバイステップのチュートリアル)?

159
xpepermint

いくつかのアプローチがあります:

ActiveSupport :: Concernの使用(推奨)

詳細については、 ActiveSupport :: Concern ドキュメントを参照してください。

libディレクトリにactive_record_extension.rbというファイルを作成します。

require 'active_support/concern'

module ActiveRecordExtension

  extend ActiveSupport::Concern

  # add your instance methods here
  def foo
     "foo"
  end

  # add your static(class) methods here
  class_methods do
    #E.g: Order.top_ten        
    def top_ten
      limit(10)
    end
  end
end

# include the extension 
ActiveRecord::Base.send(:include, ActiveRecordExtension)

config/initializersという名前のextensions.rbディレクトリにファイルを作成し、次の行をファイルに追加します。

require "active_record_extension"

継承(推奨)

Tobyの answer を参照してください。

モンキーパッチ(回避する必要があります)

config/initializersという名前のactive_record_monkey_patch.rbディレクトリにファイルを作成します。

class ActiveRecord::Base     
  #instance method, E.g: Order.new.foo       
  def foo
   "foo"
  end

  #class method, E.g: Order.top_ten        
  def self.top_ten
    limit(10)
  end
end

Jamie Zawinski による正規表現に関する有名な引用は、猿のパッチに関連する問題を説明するために再利用できます。

一部の人々は、問題に直面したとき、「私は猿のパッチを使用することを知っています。」と考えます。今、彼らは2つの問題を抱えています。

モンキーパッチは簡単かつ迅速です。しかし、節約された時間と労力は常に将来のある時点で抽出されます。複利で。最近では、モンキーパッチの適用を制限して、Railsコンソールでソリューションをすばやくプロトタイプ化します。

334
Harish Shetty

クラスを拡張するだけで、継承を使用できます。

class AbstractModel < ActiveRecord::Base  
  self.abstract_class = true
end

class Foo < AbstractModel
end

class Bar < AbstractModel
end
70
Toby Hede

ActiveSupport::Concernを使用して、さらにRailsのようにイディオムのようなコアにすることもできます。

module MyExtension
  extend ActiveSupport::Concern

  def foo
  end

  module ClassMethods
    def bar
    end
  end
end

ActiveRecord::Base.send(:include, MyExtension)

[編集] @danielからのコメントに従って

すべてのモデルには、メソッドfooがインスタンスメソッドとして含まれ、ClassMethodsのメソッドがクラスメソッドとして含まれます。例えば。 FooBar < ActiveRecord::Baseには次のものがあります:FooBar.barおよびFooBar#foo

http://api.rubyonrails.org/classes/ActiveSupport/Concern.html

21
nikola

Rails 4では、懸念を使用してモデルをモジュール化し、DRYをモデル化するという概念がハイライトされました。

懸念事項は、基本的に、モデルの類似したコードまたは単一のモジュール内の複数のモデルにまたがってコードをグループ化し、モデルでこのモジュールを使用することを可能にします。次に例を示します。

記事モデル、イベントモデル、コメントモデルについて考えてみましょう。記事またはイベントには多くのコメントがあります。コメントは記事またはイベントに属します。

従来、モデルは次のようになります。

コメントモデル:

class Comment < ActiveRecord::Base
  belongs_to :commentable, polymorphic: true
end

記事モデル:

class Article < ActiveRecord::Base
  has_many :comments, as: :commentable 

  def find_first_comment
    comments.first(created_at DESC)
  end

  def self.least_commented
   #return the article with least number of comments
  end
end

イベントモデル

class Event < ActiveRecord::Base
  has_many :comments, as: :commentable 

  def find_first_comment
    comments.first(created_at DESC)
  end

  def self.least_commented
   #returns the event with least number of comments
  end
end

お気づきのとおり、イベントモデルと記事モデルの両方に共通する重要なコードがあります。懸念事項を使用して、別のモジュールCommentableでこの共通コードを抽出できます。

このために、app/model/concernsにcommentable.rbファイルを作成します。

module Commentable
    extend ActiveSupport::Concern

    included do 
        has_many :comments, as: :commentable 
    end

    # for the given article/event returns the first comment
    def find_first_comment
        comments.first(created_at DESC)
    end

    module ClassMethods     
        def least_commented
           #returns the article/event which has the least number of comments
        end
    end 
end

そして、モデルは次のようになります。

コメントモデル:

    class Comment < ActiveRecord::Base
      belongs_to :commentable, polymorphic: true
    end

記事モデル:

class Article < ActiveRecord::Base
    include Commentable
end

イベントモデル

class Event < ActiveRecord::Base    
    include Commentable
end

懸念を使用する際に強調したい点は、「技術」グループ化ではなく「ドメインベース」グループ化に懸念を使用する必要があることです、たとえば、ドメインのグループ化は「Commentable」、「Taggable」などのようになります。技術ベースのグループ化は「FinderMethods」、「ValidationMethods」のようになります。

投稿へのリンク は、モデルの懸念を理解するのに非常に役立つことがわかりました。

記事が役立つことを願って:)

17
Aaditi Jain

ステップ1

module FooExtension
  def foo
    puts "bar :)"
  end
end
ActiveRecord::Base.send :include, FooExtension

ステップ2

# Require the above file in an initializer (in config/initializers)
require 'lib/foo_extension.rb'

ステップ

There is no step 3 :)
7
Vitaly Kushner

Rails 5は、ActiveRecord::Baseを拡張するための組み込みメカニズムを提供します。

これは、追加のレイヤーを提供することにより実現されます。

# app/models/application_record.rb
class ApplicationRecord < ActiveRecord::Base
  self.abstract_class = true
  # put your extensions here
end

すべてのモデルはそのモデルを継承します。

class Post < ApplicationRecord
end

例参照 このブログ投稿

5
Adobe

Rails 5を使用すると、すべてのモデルがApplicationRecordから継承され、他の拡張ライブラリを含めたり拡張したりする素敵な方法が提供されます。

# app/models/concerns/special_methods.rb
module SpecialMethods
  extend ActiveSupport::Concern

  scope :this_month, -> { 
    where("date_trunc('month',created_at) = date_trunc('month',now())")
  }

  def foo
    # Code
  end
end

すべてのモデルで特別なメソッドモジュールを使用する必要がある場合、application_record.rbファイルに含めます。特定のモデルセットにこれを適用する場合は、それぞれのモデルクラスに含めます。

# app/models/application_record.rb
class ApplicationRecord < ActiveRecord::Base
  self.abstract_class = true
  include SpecialMethods
end

# app/models/user.rb
class User < ApplicationRecord
  include SpecialMethods

  # Code
end

モジュールでクラスメソッドとしてメソッドを定義する場合は、モジュールをApplicationRecordに拡張します。

# app/models/application_record.rb
class ApplicationRecord < ActiveRecord::Base
  self.abstract_class = true
  extend SpecialMethods
end

それが他の人を助けることを願っています!

4
Ashik Salman

このトピックに追加するために、このような拡張機能をテストする方法を模索しました(ActiveSupport::Concernルートに進みました)。

拡張機能をテストするためのモデルを設定する方法は次のとおりです。

describe ModelExtensions do
  describe :some_method do
    it 'should return the value of foo' do
      ActiveRecord::Migration.create_table :test_models do |t|
        t.string :foo
      end

      test_model_class = Class.new(ActiveRecord::Base) do
        def self.name
          'TestModel'
        end

        attr_accessible :foo
      end

      model = test_model_class.new(:foo => 'bar')

      model.some_method.should == 'bar'
    end
  end
end
4
Will Tomlins

私は持っています

ActiveRecord::Base.extend Foo::Bar

初期化子で

以下のようなモジュールの場合

module Foo
  module Bar
  end
end
0
Ed Richards