Документация для :finder_sql
ужасно неполна, и пример кода не работает. Как вы обнаружили, это:
has_many :subscribers, :class_name => "User", :finder_sql =>
'SELECT DISTINCT people.* ' +
'FROM people p, post_subscriptions ps ' +
'WHERE ps.post_id = #{id} AND ps.person_id = p.id ' +
'ORDER BY p.first_name'
не будет работать и, основываясь на источнике ActiveRecord, не может работать. Если вы проверите источник, вы увидите такие вещи :
def custom_finder_sql
interpolate(options[:finder_sql])
end
, а затем interpolate
делает это:
def interpolate(sql, record = nil)
if sql.respond_to?(:to_proc)
owner.send(:instance_exec, record, &sql)
else
sql
end
end
, так что если ваш :finder_sql
является просто строкой (как в примере), то он используется как есть, без интерполяции вообще, и в итоге вы получите неработающий SQL. Если вы хотите интерполяцию, то вам нужно будет получить interpolate
для ввода первой ветви, так что вы захотите лямбду для :finder_sql
и строку в двойных кавычках внутри лямбды, чтобы #{id}
работал:
has_many :subscribers, :class_name => "User", :finder_sql => ->(record) do
"SELECT DISTINCT people.* " +
"FROM people p, post_subscriptions ps " +
"WHERE ps.post_id = #{id} AND ps.person_id = p.id " +
"ORDER BY p.first_name"
end
Это должно попасть в первую ветку внутри interpolate
, так что вызов instance_exec
будет оценен и интерполирует строку в контексте рассматриваемого объекта. Я не уверен, когда record
не будет nil
, так что вы можете вместо этого:
has_many :subscribers, :class_name => "User", :finder_sql => ->(record) do
record = self if(record.nil?)
"SELECT DISTINCT people.* " +
"FROM people p, post_subscriptions ps " +
"WHERE ps.post_id = #{record.id} AND ps.person_id = p.id " +
"ORDER BY p.first_name"
end
И пока мы здесь, пожалуйста, используйте явные условия соединения вместо неявных:
has_many :subscribers, :class_name => "User", :finder_sql => ->(record) do
record = self if(record.nil?)
"SELECT DISTINCT people.* " +
"FROM people p " +
"JOIN post_subscriptions ps on p.id = ps.person_id " +
"WHERE ps.post_id = #{record.id} " +
"ORDER BY p.first_name"
end
Блог, который вы нашли об одинарных / двойных кавычках и :finder_sql
:
http://tamersalama.com/2007/05/17/finder_sql-single-vs-double-quotes/
устарел и, похоже, не относится к Rails 3+. Выше приведены выдержки из 3.1, но поведение, которое вы видите, указывает на то, что код и поведение, вероятно, изменились в 3.0, но документация не была обновлена.