SMALL MAKE

by EIJI NAKAI

PROGRAMING

Ruby & Rails

Rails4: ActiveRecord polymorphicのjoins検索?(追記あり)

2014-09-11 19:15

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)