@kyanny's blog

My life. Opinions are my own.

ActiveRecord::Base#find で find(:all, :conditions => { :key => [1,2,3] }) とすると SQL の WHERE 句が `key` IN (1,2,3) になるしくみ


AWDwR 3rd Edition によると Rails 1.2 から ActiveRecord::Base#find の :conditions に Hash を渡せるようになったようで、その際にログを眺めてたら実行される SQL の WHERE 句が IN () を使っていた。これをどこでやってんのか気になったのでソースを追ってみた。 Rails 2.3.9 で確認。

activerecord/base.rb のメソッド呼び出しを追うと以下のようになってて、

find ->
find_every ->
find_by_sql ->
construct_finder_sql ->
add_conditions! ->
merge_conditions ->
sanitize_sql -> (alias_method)
sanitize_sql_for_conditions ->
sanitize_sql_hash_for_conditions ->
attribute_condition

attribute_condition の中でやってた。まぁ IN で grep すれば該当箇所はすぐ見つかるんだけど、トップダウンで追うのも流れをおさえるにはいいかなと思って。

        def attribute_condition(quoted_column_name, argument)
          case argument
            when nil   then "#{quoted_column_name} IS ?"
            when Array, ActiveRecord::Associations::AssociationCollection, ActiveRecord::NamedScope::Scope then "#{quoted_column_name} IN (?)"
            when Range then if argument.exclude_end?
                              "#{quoted_column_name} >= ? AND #{quoted_column_name} < ?"
                            else
                              "#{quoted_column_name} BETWEEN ? AND ?"
                            end
            else            "#{quoted_column_name} = ?"
          end
        end

書籍やマニュアルであんまり詳しく述べられてない内部の挙動*1に疑問があるときはソースを読むと自信をもって機能を使えてよいですね。

RailsによるアジャイルWebアプリケーション開発 第3版

RailsによるアジャイルWebアプリケーション開発 第3版

*1:SQL の WHERE 句がどうなるか、とか