with_scopeをprotectedにするということは

こんな感じになるということなんですかね?という試行錯誤。

悪くないとは思うんですが、慣れるまでは大変そう。
なんていいながら実はけっこうクラス内でwith_scopeするのは好きなんですけどね。

class Blog < ActiveRecord::Base
  has_many :entries
end
class Entry < ActiveRecord::Base
  belongs_to :blog
  validates_presence_of :title, :body, :null => false

  class << self
    def find_with_deleted_flag_skip(*args)
      with_scope(:find=>{:conditions=>{:deleted=>false}}) do
        find_without_deleted_flag_skip(*args)
      end
    end
    alias_method_chain :find, :deleted_flag_skip
  end
end

実際に試した結果。

Blog.find(1).entries.find(:all)

実行されるクエリ

 SELECT * FROM blogs WHERE (blogs."id" = 1)
 SELECT * FROM entries WHERE (entries."deleted" = 'f') AND (entries.blog_id = 1)

オーケー。削除フラグをケアしてますね。

念のための補足しておくと、これはwith_scopeで以下のように書いたのと同じSQLを吐いてます。

Entry.with_scope(:find=>{:conditions=>{:deleted=>false}}) do
  Entry.find(:all, :conditions=>{:blog_id=>1})
end

ポイントは二つ。

まずfindをオーバーライド(じゃないけど、まぁそんなイメージで)してwith_scopeでの削除フラグ関連をモデル側に寄せたこと。
そしてHasManyAssociation#find()でもモデルクラスでオーバーライドされたfind()メソッドが使用されていること。HasManyAssociation#find()は親レコード側のIDをWHERE句にくっつけてくれるんですよね(entries.blog_id = 1の部分)。