find_by_sql_with_deleted
acts_as_paranoidはレコードを論理削除してくれるRailsプラグインで、findの条件節に自動的にdeleted_at IS NULLとか付けてくれるわけなんだけど、どうもfind_by_sqlはその範囲外らしい。
by_sqlって付けてるんだからそのSQLをそのまま実行したいという気持ちは分からんでもないけど、そこだけ自力でdeleted_at IS NULLとかつけるのも気持ち悪いので無理矢理作ってみた。
とりあえずCaboose::Acts::ParanoidのClassMethodsに追加したらそれなりに動いてる気がする。
def find_by_sql(sql) ar_tables = Object.subclasses_of(ActiveRecord::Base).inject({}) do |hash, ar| hash[ar.table_name] = ar hash end froms = if (sql.is_a?(String) ? sql : sql.first) =~ /from\s+(\w+(\s+as\s+\w+)?(\s*,\s*\w+(\s+as\s+\w+)?)*)/im $1.split(',').map{|s| s.split(/\s+as\s+/im).map{|t| t.strip}} end additional_condition = froms.map do |from| tname, aname = from[1] ? from : [from.first, from.first] if ar_tables[tname].paranoid? "#{aname}.deleted_at IS NULL" end end.uniq.compact.join ' AND ' additional_condition += ' AND' unless additional_condition.empty? sql = case sql when String sql.sub /\bwhere\b/i, "\\0 #{additional_condition}" when Array [sql[0].sub(/\bwhere\b/i, "\\0 #{additional_condition}"), *sql[1..-1]] end connection.select_all(sanitize_sql(sql), "#{name} Load").collect! { |record| instantiate(record) } end
まともに確認してないので、もしかしたらなんか変な副作用あるかも。
あと、テーブル名からAR名引くために無理やりObject#subclasses_ofとかしてるので重そう。なんかいいやり方があったら教えてください。