私のモデルがいくつかの特別なメソッドを持つように、 ActiveRecord:Base クラスを拡張する方法についていくつか読んだことがあります。それを拡張する簡単な方法は何ですか (ステップバイステップのチュートリアル)?
9 に答える
いくつかのアプローチがあります:
ActiveSupport :: Concernの使用(推奨)
詳細については、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"
継承(推奨)
Tobyの回答を参照してください。
モンキーパッチ(避けるべき)
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
ジェイミー・ザウィンスキーによる正規表現に関する有名な引用は、モンキーパッチに関連する問題を説明するために再利用できます。
問題に直面したとき、「わかっている、モンキーパッチを使う」と考える人もいます。今、彼らは2つの問題を抱えています。
モンキーパッチは簡単かつ迅速です。しかし、節約された時間と労力は常に将来いつか引き戻されます。複利で。最近では、モンキーパッチを制限して、レールコンソールでソリューションのプロトタイプをすばやく作成しています。
クラスを拡張して、継承を使用するだけです。
class AbstractModel < ActiveRecord::Base
self.abstract_class = true
end
class Foo < AbstractModel
end
class Bar < AbstractModel
end
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
Rails 4 では、モデルをモジュール化して DRY アップするために懸念を使用するという概念が注目されています。
懸念事項を使用すると、基本的に、モデルの類似コードまたは複数のモデルを 1 つのモジュールにグループ化し、このモジュールをモデルで使用できます。次に例を示します。
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 :)
このトピックに追加するために、私はそのような拡張機能をテストする方法を検討するのにしばらく時間を費やしました (私は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
私は持っている
ActiveRecord::Base.extend Foo::Bar
イニシャライザで
以下のようなモジュールの場合
module Foo
module Bar
end
end