おおいしつかさ


旅行とバイクとドライブと料理と宇宙が好き。
Ubie Discoveryのプログラマ。
Share:  このエントリーをはてなブックマークに追加

Rails2.1.2でActsAsReadonlyableが動かないときの対処

Railsのバージョンを2.1.2にあげたらvalidates_uniquness_ofでActiveRecord::StatementInvalid例外が出るようになった。

TypeError: wrong argument type Hash (expected String): .......  

vendor/rails/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb:147:in `log'  
vendor/rails/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb:302:in `execute'  
vendor/rails/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb:537:in `select'  
vendor/rails/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb:7:in `select_all_without_query_cache'  
vendor/rails/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb:59:in `select_all'  
vendor/rails/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb:80:in `cache_sql'  
vendor/rails/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb:59:in `select_all'  
vendor/rails/activerecord/lib/active_record/validations.rb:651:in `validates_uniqueness_of'  

vendor/rails/activerecord/lib/active_record/validations.rbの651行目を見てみる。

results = finder_class.with_exclusive_scope do  
  connection.select_all(  
    construct_finder_sql(  
      :select     => "#{connection.quote_column_name(attr_name)}",  
      :from       => "#{finder_class.quoted_table_name}",  
      :conditions => [condition_sql, *condition_params]  
    )  
  )  
end  

どうも、select_allに文字列のSQLを渡さなきゃいけないのに、Hashが渡っていることでエラーになっている。
なので、construct_finder_sqlメソッドを見てみる。

        def construct_finder_sql(options)  
          scope = scope(:find)  
          sql  = "SELECT #{options[:select] || (scope && scope[:select]) || ((options[:joins] || (scope && scope[:joins])) && quoted_table_name + '.*') || '*'} "  
          sql << "FROM #{(scope && scope[:from]) || options[:from] || quoted_table_name} "  

          add_joins!(sql, options, scope)  
          add_conditions!(sql, options[:conditions], scope)  

          add_group!(sql, options[:group], scope)  
          add_order!(sql, options[:order], scope)  
          add_limit!(sql, options, scope)  
          add_lock!(sql, options, scope)  

          sql  
        end  

それぞれのメソッドもたどって見たけど、このメソッドはちゃんと文字列のSQLを返していた。どこかで悪さをしているやつがいるらしい。
と思ってプラグインを調べたらActsAsReadonlyableが犯人だった。


      def construct_finder_sql(options)  
        options.merge(:sql => super)  
      end  

こんなことしている。なので、select_allをオーバライドして仮対処してみた。

module ActiveRecord  
  module ConnectionAdapters  
    class AbstractAdapter  
      def select_all(sql, name = nil)  
        sql = sql[:sql] if sql.is_a?(Hash)  
        select(sql, name)  
      end  
    end  
  end  
end