Thanks Driven Life

日々是感謝

include_conditions

仕事で触ってるRailsを、本番環境ではなくローカルで開発するために
そのまま scp して持ってきて rubyrails のバージョンもあわせているのに
なぜか動かない。こういうエラーが出ます

  Unknown key(s): include_conditions

include_conditions ってのはなんぞやってググってみると

http://d.hatena.ne.jp/osakanas/20070102/p1

これですね。便利だなと思いながらもなぜ動かない。
少なくとも本番環境では動いているのに。謎だ。
とエラーをよく見ると、:include_conditions が登録されていないとのこと。
上のページのやつと比較すると、さりげなく

class Base
    VALID_FIND_OPTIONS = [
        :conditions, :include, :joins, :limit, :offset,
        :order, :select, :readonly, :group, :from, :include_conditions ]
end

が書かれていなかったので、「これが原因か!」と思い足してみたが、やはり変わらず。
起動時には読み込まれているらしいが、実行中にはすでに
VALID_FIND_OPTIONS が元のライブラリでの宣言の状態に戻ってしまっている。
ちなみに元の状態ってのがこれ

    VALID_FIND_OPTIONS = [
        :conditions, :include, :joins, :limit, :offset,  
        :order, :select, :readonly, :group, :having, :from, :lock ]

(どこか)/lib/active_record/base.rb では、
VALID_FIND_OPTIONS は protected になっているため、
include_with_conditions.rbで定義しても意味がない。

ということは、base.rb で宣言されたVALID_FIND_OPTIONS に対して、
実行中に :include_conditions を追加すればいいんだなと思った。
問題はどのタイミングで追加するのか。
include_with_conditions.rb で定義(オーバーライドというのかな)されてるメソッドでは
すでに options が validation ほげほげでエラーが出ているのでだめ。
タイミング的には find の所だろう。ということで、find をオーバーライドすることにしました。

module ActiveRecord
  class Base
    class << self
      def find(*args)
        VALID_FIND_OPTIONS << :include_conditions
	VALID_FIND_OPTIONS.uniq!                      

        # 以下は既存の find と同じ
        options = args.extract_options!
        validate_find_options(options)
        set_readonly_option!(options)

        case args.first
        when :first then find_initial(options)
        when :last  then find_last(options)
        when :all   then find_every(options)
        else             find_from_ids(args, options)
        end
      end
    end
  end

  module Associations
    module ClassMethods
      def select_all_rows(options, join_dependency)
  # 以下、参考ページと同じ

find するたびに :include_conditions が増えていくので
uniq! を実行して :include_conditions を一つにしているというアホなコードです。
Arrayのメソッドで「〜の要素を持っている場合は真」的なメソッドがあったようななかったような。

ちなみに VALID_FIND_OPTIONS は validate_find_options の中で使っているので
その中で VALID_FIND_OPTIONS とは別の定数を使って
validate すれば、毎回追加とかしなくていいんじゃね?って話なんだけど
残念ながら validate_find_options は protected method なのよね。。。


だれかもう少しマシなコードお願いします