web-dev-qa-db-ja.com

Rails:なぜwith_exclusive_scopeが保護されているのですか?それを使用する方法についての良い習慣はありますか?

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ウェイになることはできません!?

46
RngTng

これを行うRails3の方法をお探しの方は、unscopedメソッドを使用できます。

Ticket.unscoped.all
173
brad

可能であれば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のようなより慣用的な日時列名の使用を検討してください。

34
Ryan McGeary

次のように、保護されたメソッドをモデルメソッド内にカプセル化する必要があります。

class Ticket < ActiveRecord::Base
  def self.all_tickets_from(user)
    with_exclusive_scope{user.tickets.find(:all)}
  end
end
20
Vlad Zloteanu