ActiveRecord:Baseクラスを拡張してモデルにいくつかの特別なメソッドを追加する方法についていくつか読んだことがあります。それを拡張する簡単な方法は何ですか(ステップバイステップチュートリアル)?
ActiveRecord:Baseクラスを拡張してモデルにいくつかの特別なメソッドを追加する方法についていくつか読んだことがあります。それを拡張する簡単な方法は何ですか(ステップバイステップチュートリアル)?
回答:
いくつかのアプローチがあります:
詳細については、ActiveSupport :: Concernのドキュメントをご覧ください。
ファイルを作成active_record_extension.rbしてlibディレクトリを。
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"トビーの答えを参照してください。
という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
endJamie Zawinskiによる正規表現に関する有名な引用は、サルのパッチングに関連する問題を説明するために再利用できます。
一部の人々は、問題に直面したとき、「わかっている、私はサルのパッチを使用する」と思います。今、彼らは2つの問題を抱えています。
サルのパッチは簡単かつ迅速です。ただし、節約された時間と労力は、常に将来のある時点で戻されます。複利で。最近、私はRailsコンソールでソリューションを迅速にプロトタイプ化するために、サルのパッチ適用を制限しています。
requireの最後のファイルにする必要がありますenvironment.rb。私はこの追加のステップを私の答えに追加しました。
                    ImprovedActiveRecordそこから継承する必要があります。を使用moduleしている場合は、問題のクラスの定義を更新します。私は継承を使用していました(長年のJava / C ++の経験が原因)。最近は主にモジュールを使用しています。
                    Refinementsサルのパッチに関する問題のほとんどに対処するという新しい機能が導入されています(yehudakatz.com/2010/11/30/ruby-2-0-refinements-in-practice)。運命を誘惑するためだけに機能が存在する場合があります。そして時にはあなたはそうします。
                    クラスを拡張するだけで、継承を使用できます。
class AbstractModel < ActiveRecord::Base  
  self.abstract_class = true
end
class Foo < AbstractModel
end
class Bar < AbstractModel
endabstract_models。どこに置けばいいですか?
                    self.abstract_class = trueしますAbstractModel。Railsはモデルを抽象モデルとして認識します。
                    AbstractModelがデータベース内を探して窒息したときはあきらめました。簡単なセッターが物事を乾かすのに役立つだろうと誰が知っていましたか?(私はうんざりし始めていた...それは悪かった)。トビーとハリッシュに感謝!
                    次の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
InstanceMethodsRails 3.2から非推奨になっていることに注意してください。メソッドをモジュール本体に配置するだけです。
                    ActiveRecord::Base.send(:include, MyExtension)はイニシャライザを配置しましたが、これでうまくいきました。Rails 4.1.9
                    Rails 4では、懸念事項を使用してモデルをモジュール化して乾燥させるという概念が強調されています。
懸念事項により、基本的には、モデルの類似したコードまたは複数のモデルにまたがる単一のモジュールにコードをグループ化し、このモジュールをモデルで使用できます。次に例を示します。
Articleモデル、Eventモデル、Commentモデルを考えてみましょう。記事またはイベントには多くのコメントがあります。コメントは記事またはイベントのいずれかに属しています。
従来、モデルは次のようになります。
コメントモデル:
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懸念を使用する際に強調したい点の1つは、懸念は「技術」グループではなく「ドメインベース」グループに使用する必要があることです。たとえば、ドメイングループは「コメント可能」、「タグ付け可能」などです。技術ベースのグループは「FinderMethods」、「ValidationMethods」のようになります。
これは、モデルの問題を理解するのに非常に役立つと思う投稿へのリンクです。
記述が役立つことを願っています:)
ステップ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'ステップ3
There is no step 3 :)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たとえば、このブログ投稿を参照してください。
このトピックに追加するために、そのような拡張機能をテストする方法を検討するのにしばらく時間を費やしました(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
endRails 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それが他の人を助けることを願っています!