読者です 読者をやめる 読者になる 読者になる

Associationは書けないんだけどINNER JOINしたテーブルのカラムを参照したいんです

active record

たぶんPrimaryKeyじゃないカラムで紐付けあっているテーブルだとbelongs_toとかでAssociationを定義できない?気がしています。試していないんですけど。

そんなときに結合したテーブルのカラムを触りたい場合のやり方を2通り。

  1. ターゲットになるテーブルのActiveRecord::Relationを取得するメソッドを作る
  2. joinsは普通に書いて、selectに対象テーブル名付きでカラム名を指定するを書く(2013/10/13訂正 なんでこう書いたんや。。)

ターゲットになるテーブルのActiveRecord::Relationを取得するメソッドを作る

class Employee
  def job_history
    JobHistory.where(employee_id: employee_id)
  end
end

Employee.find(101).job_history.each do |r|
  puts r.inspect
end
# => #<JobHistory employee_id: 101, start_date: "1997-09-21 00:00:00", end_date: "2001-10-27 00:00:00", job_id: "AC_ACCOUNT", department_id: 110>
# => #<JobHistory employee_id: 101, start_date: "2001-10-28 00:00:00", end_date: "2005-03-15 00:00:00", job_id: "AC_MGR", department_id: 110>

scopeにできればもっとすっきりしそうなものだけど……

joinsは普通に書いて、selectに対象テーブル名付きでカラム名を指定するを書く

joinsはもう少し簡単な書き方あります。。

emp = Employee.arel_table
hist = JobHistory.arel_table
join_str = emp.join(hist).on(
  emp[:employee_id].eq(hist[:employee_id])
  ).join_sources
Employee.select(hist[Arel.sql('*')]).joins(join_str).where(employee_id: 101).each do |r|
  puts "#{r.inspect} and JobHistory attributes<start_date: #{r.start_date}, end_date: #{r.end_date}>"
end
# => #<Employee employee_id: 101, job_id: "AC_ACCOUNT", department_id: 110> and JobHistory attributes<start_date: 1997-09-21 00:00:00 +0900, end_date: 2001-10-27 00:00:00 +0900>
# => #<Employee employee_id: 101, job_id: "AC_MGR", department_id: 110> and JobHistory attributes<start_date: 2001-10-28 00:00:00 +0900, end_date: 2005-03-15 00:00:00 +0900>

joinした側のテーブルのカラムのアクセサをしれっと呼び出せばいける。

参考

メモ

ArelでOUTER JOINを書きたかったら多分emp.join(hist, Arel::Nodes::OuterJoin).on(略)って書くのかなー。

参考:sql - ActiveRecord/ARel modify ON in a left out join from includes - Stack Overflow