polymorphicをjoinsで記述する方法が分からず、ほとんどSQLで書いたことのメモです。
例えば動物と植物のデータテーブルがあって、研究報告書のテーブルを共有して使うような構造。
class Report < ActiveRecord::Base belongs_to :reportable, polymorphic: true end
class Animal < ActiveRecord::Base has_many :report, as: :reportable, dependent: :destroy end
class Plant < ActiveRecord::Base has_many :report, as: :reportable, dependent: :destroy end
動物のコアラと植物のユーカリのレポートを検索して一覧に表示したい。
ここでの前提は、何らかの検索の結果としてのReportのコレクション reports が手元にあり、ここから検索を追加記述しなければならないということ。(つまり AnimalやPlan側からの開始でReportを抽出できない)
joinsで検索を追加できるだろうか?
調べたが分からなかったので、とりあえず期待を込めてこうだったらいいなで書いてみる。
koala_reports = repors.joins(:animals).where(:animals => {:specie => KOALA}) eucalyptus_reports = repors.joins(:plants).where(:plants => {:classification => EUCALYPTUS}) result = koala_reports | eucalyptus_reports
残念、やっぱりダメで1〜2行目で report は animalを持っていない、plants を持っていないという意味でエラーになる。ではreportabelだろうかとヤマカンをはる(多分かなり疲れていた)。
koala_reports = repors.joins(:reportabel).where(:animals => {:specie => KOALA}) eucalyptus_reports = repors.joins(:reportabel).where(:plants => {:classification => EUCALYPTUS}) result = koala_reports | eucalyptus_reports
当然、これも間違い。
仕方ないので、SQLでベタに書くことにした。
koala_reports = repors.joins("JOIN animals ON animais.id = reports.reportable_id AND reports.reportable_type = 'Animal' AND animals.specie = #{KOALA}") eucalyptus_reports = repors.joins("JOIN plants ON plants.id = reports.reportable_id AND reports.reportable_type = 'Plant' AND plants.classification = #{EUCALYPTUS}") result = koala_reports | eucalyptus_reports
なにかよい記述方法があるのだろうか。
【追記】
多分、repors.animals と repors.plants でアクセスできるようにモデルを書きかえた上で(前提が変わるか?)、以下で行けるのでは? Arelを使う。2015/03/04
result = repors.includes(:animals, :plants) .where(Animal.arel_table[:specie].eq(KOALA) .or(Plant.arel_table[:classification].eq(EUCALYPTUS))) .references(:animals, :plants)