ActiveRecordアソシエーションによって提供されるメソッドの1つをオーバーライドする方法はありますか?
たとえば、次の典型的なポリモーフィックhas_many:throughassociationがあるとします。
class Story < ActiveRecord::Base
has_many :taggings, :as => :taggable
has_many :tags, :through => :taggings, :order => :name
end
class Tag < ActiveRecord::Base
has_many :taggings, :dependent => :destroy
has_many :stories, :through => :taggings, :source => :taggable, :source_type => "Story"
end
ご存知かもしれませんが、これにより、tags、tags <<、tags =、tags.empty?などの関連するメソッドがストーリーモデルに多数追加されます。
これらのメソッドの1つをオーバーライドするにはどうすればよいですか?具体的には、tags <<メソッドです。通常のクラスメソッドをオーバーライドするのは非常に簡単ですが、関連付けメソッドをオーバーライドする方法に関する情報が見つからないようです。次のようなことをする
def tags<< *new_tags
#do stuff
end
呼び出されると構文エラーが発生するため、明らかにそれほど単純ではありません。
has_many
でブロックを使用して、メソッドとの関連付けを拡張できます。コメント「ブロックを使用して関連付けを拡張する」を参照してください ここ 。
既存のメソッドをオーバーライドすることもできますが、それが良い考えかどうかはわかりません。
has_many :tags, :through => :taggings, :order => :name do
def << (value)
"overriden" #your code here
super value
end
end
Rails 3.2でモデル自体にアクセスする場合は、proxy_association.owner
を使用する必要があります
例:
class Author < ActiveRecord::Base
has_many :books do
def << (book)
proxy_association.owner.add_book(book)
end
end
def add_book (book)
# do your thing here.
end
end
ドキュメント を参照してください
<<
メソッドを持つオブジェクトを返すには、tagsメソッドを定義する必要があります。
このようにすることもできますが、私は本当にお勧めしません。 ActiveRecordが使用するものを置き換えようとするよりも、モデルに必要なことを実行するメソッドを追加する方がはるかに良いでしょう。
これは基本的にデフォルトのtags
メソッドを実行し、結果のオブジェクトに<<メソッドを追加して、そのオブジェクトを返します。実行するたびに新しいメソッドが作成されるため、これは少しリソースを消費する可能性があります
def tags_with_append
collection = tags_without_append
def collection.<< (*arguments)
...
end
collection
end
# defines the method 'tags' by aliasing 'tags_with_append'
alias_method_chain :tags, :append
署名にはdef tags.<<(*new_tags)
が必要だと思います。これは機能するはずです。または、複数のメソッドをオーバーライドする必要がある場合は、同等で少しクリーンな次のものが必要です。
class << tags
def <<(*new_tags)
# rawr!
end
end
これはあなたの場合には役に立たないかもしれませんが、これを調べている他の人には役立つかもしれません。
アソシエーションコールバック: http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html
ドキュメントからの例:
class Project
has_and_belongs_to_many :developers, :after_add => :evaluate_velocity
def evaluate_velocity(developer)
...
end
end
アソシエーション拡張機能も参照してください。
class Account < ActiveRecord::Base
has_many :people do
def find_or_create_by_name(name)
first_name, last_name = name.split(" ", 2)
find_or_create_by_first_name_and_last_name(first_name, last_name)
end
end
end
person = Account.first.people.find_or_create_by_name("David Heinemeier Hansson")
person.first_name # => "David"
person.last_name # => "Heinemeier Hansson"
私が使用する方法は、関連付けを拡張することです。ここで「数量」属性を処理する方法を確認できます: https://Gist.github.com/1399762
それは基本的にあなたがただすることを可能にします
has_many : tags, :through => : taggings, extend => QuantityAssociation
メソッドをオーバーライドすることによって何を達成したいのかを正確に知らなければ、同じことができるかどうかを知ることは困難です。