default_scopeのモデルを指定して、古いエントリをすべてフィルタリングします。
# == Schema Information
#
# id :integer(4) not null, primary key
# user_id :integer(4) not null, primary key
# end_date :datetime
class Ticket < ActiveRecord::Base
belongs_to :user
default_scope :conditions => "tickets.end_date > NOW()"
end
anyチケットを取得したいと思います。この場合、with_exclusive_scopeが有効ですが、このメソッドは保護されていますか?これだけが機能します:
Ticket.send(:with_exclusive_scope) { find(:all) }
一種のハックですね。それで、正しい使い方は何ですか?特にアソシエーションを扱う場合、さらに悪化します(ユーザーが多くのチケットを持っている場合)。
Ticket.send(:with_exclusive_scope) { user.tickets.find(:all) }
それはso醜いです!!! -Railsウェイになることはできません!?
これを行うRails3の方法をお探しの方は、unscoped
メソッドを使用できます。
Ticket.unscoped.all
可能であればdefault_scope
を避けます。なぜdefault_scope
が必要なのか、もう一度考え直してください。 default_scope
に対抗することは、その価値よりも厄介であることが多く、まれな場合にのみ使用する必要があります。また、default_scope
を使用しても、チケットモデルの外部でチケットの関連付けにアクセスした場合は、あまりわかりません(例 "account.tickets
に電話しました。チケットがそこにないのはなぜですか?")。これは、with_exclusive_scope
が保護されている理由の一部です。あなたはそれを使用する必要があるとき、あなたはいくつかの 構文酢 を味わうべきです。
別の方法として、モデルに便利なnamed_scopesを自動的に追加する pacecar のようなgem/pluginを使用すると、どこでもより明確なコードが得られます。例えば:
class Ticket < ActiveRecord::Base
include Pacecar
belongs_to :user
end
user.tickets.ends_at_in_future # returns all future tickets for the user
user.tickets # returns all tickets for the user
上記のコードをよりクリーンにするために、ユーザーモデルを装飾することもできます。
Class User < ActiveRecord::Base
has_many :tickets
def future_tickets
tickets.ends_at_in_future
end
end
user.future_tickets # returns all future tickets for the user
user.tickets # returns all tickets for the user
補足:また、ends_at
ではなくend_date
のようなより慣用的な日時列名の使用を検討してください。
次のように、保護されたメソッドをモデルメソッド内にカプセル化する必要があります。
class Ticket < ActiveRecord::Base
def self.all_tickets_from(user)
with_exclusive_scope{user.tickets.find(:all)}
end
end