acts_as_paranoidで関連を扱う場合
acts_as_paranoidとはモデルを論理削除できるようにするrailsプラグインです。
簡単な使用では問題ないのですが
関連を使った場合には消したデータを見てしまう可能性がありました。
やりたいこと
例として学校クラスと生徒クラスがあったとして
学校を削除できたとする。(過疎化、少子化のせいですかねぇー)
この場合に生徒一覧を取得する、但し削除した学校の生徒は出さない
といったことをする
クラス
class School < ActiveRecord::Base acts_as_paranoid has_many :students end class Student < ActiveRecord::Base belongs_to :school end
方法と結果
1番
School.students.find(:all)
OK.問題ない
2番
Student.find(:all, :include=>:school, :condition=>"school.created_at > '2001/1/1'")
NG.削除した学校の生徒も取得してしまう
3番
Student.find(:all, :include=>:school)
OK.これは大丈夫
説明
このプラグインはacts_as_paranoidと定義してあるモデルからfindした場合にしか
発動しないらしい。(なんちゃってソース見で)
そのため2番目のがNGになる。
(Studentにはacts_as_paranoidを定義していないせい)
では、3番目のがOKになるのは何故か?
それは恐らくrails2.1だからだろう。
rails2.1から単純な結合はjoinを使った1回のsqlではなく
各モデルに対する2回のsqlに分けるようになったためだ。
動作としてStudentを取得するsqlを発行後に、Schoolを取得するsqlを発行する。
ということでShoolに対してfindしてるのでacts_as_paranoidの対象となる。
じゃあ、何故2番目の例がNGになるかというと
conditionに結合先の条件が入っているためだ。この場合はrails2.0以前のものと動作が同じになり
joinする1回のsqlになる。
2番目の場合の回避策としてはconditionに明示的にdeleted_at is nullとのチェック処理を入れることで
対応できる。(まぁ、あたりまえですねぇ。。自動で関連先も見る機能がほしいけどやっぱ複雑なんだろうなぁ。。)
実行環境
rails2.1.1