ActiveRecord:Baseクラスを拡張して、モデルにいくつかの特別なメソッドを追加する方法について、いくつか読んでいます。それを拡張する簡単な方法は何ですか(ステップバイステップのチュートリアル)?
いくつかのアプローチがあります:
詳細については、 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コンソールでソリューションをすばやくプロトタイプ化します。
クラスを拡張するだけで、継承を使用できます。
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をモデル化するという概念がハイライトされました。
懸念事項は、基本的に、モデルの類似したコードまたは単一のモジュール内の複数のモデルにまたがってコードをグループ化し、モデルでこのモジュールを使用することを可能にします。次に例を示します。
記事モデル、イベントモデル、コメントモデルについて考えてみましょう。記事またはイベントには多くのコメントがあります。コメントは記事またはイベントに属します。
従来、モデルは次のようになります。
コメントモデル:
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」のようになります。
投稿へのリンク は、モデルの懸念を理解するのに非常に役立つことがわかりました。
記事が役立つことを願って:)
ステップ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 :)
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
例参照 このブログ投稿 。
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
それが他の人を助けることを願っています!
このトピックに追加するために、このような拡張機能をテストする方法を模索しました(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