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