たとえば、エイリアス名を付けるにはどうすればよいですか。 includes()
?以下が与えられます:
ここにいくつかの例があります:
最初のケース(より多くのSTI関連)
_Project.all.includes(:students, :teachers).order('teachers_projects.name ASC') # order on teachers
Project.all.includes(:students, :teachers).order('users.name ASC') # order on students
_
Railsは、SQLの_teachers_projects
_にエイリアス名_:teachers
_を自動的に使用します。 SQLで_teachers_projects
_の代わりにエイリアス名teachers
を使用できるように、これを上書きするにはどうすればよいですか? _:students
_はエイリアス名users
を取得します。
この例は失敗します:
_Project.all.includes(:students, :teachers).order('teachers.name ASC')
Project.all.includes(:students, :teachers).order('students.name ASC')
Project.all.includes(:students, :teachers).order('students_projects.name ASC')
_
2番目のケース(1つのSTIアソシエーション)
メソッドincludes()
で_:students
_のみ(_:teachers
_なし)を使用する場合、RailsはSTI基本クラス名の名前エイリアスを使用しますusers
(__projects
_が添付されていない)_:students
_の場合:
_Project.all.includes(:students).order('users.name ASC') # order on students
_
この例は失敗します:
_Project.all.includes(:students).order('students.name ASC')
Project.all.includes(:students).order('students_projects.name ASC')
_
[〜#〜]質問[〜#〜]
次のようなものが存在する可能性があります。
_Project.all.includes(:students).alias(students: :my_alias)
_
Rails ALIAS TRACKER
テストアプリ
Arelには実際にはエイリアスメソッドがあります。
student_alias = Student.arel_table.alias(:my_student_table_alias)
警告:これには、さらに手作りのアレルを使用し、手動で結合する必要があります。また、Arelの結合は、慣れていない場合は少し複雑になる可能性があります。
student_alias_join = student_alias.create_on(
Project.arel_table[:primary_key].eq(student_alias[:project_id])
)
Project.joins(
Project.arel_table.create_join(
student_alias, student_alias_join, Arel::Nodes::OuterJoin
)
).order(...)
このような何かがそれを行う必要があります。もちろん、これを:my_student_table_alias
をパラメーターとして使用してClassメソッドに入れると、コントローラーで少し乱雑に見えるため、より整理されて再利用可能になります。
この問題に対して別のアプローチを取ります。.alias
メソッドを使用してクエリのエイリアス名を制御する代わりに、Rails/Arelに処理させますスコープ内で必要な場合はいつでも、正しいテーブル名(エイリアスかどうか)を検索するだけです。
このヘルパーメソッドをモデルに追加します。これにより、スコープから呼び出して、テーブル名がエイリアスされた(同じテーブルでの複数の結合)JOIN
内でスコープが使用されているかどうかを知ることができます。または、一方、スコープにテーブル名のエイリアスがない場合。
def self.current_table_name
current_table = current_scope.arel.source.left
case current_table
when Arel::Table
current_table.name
when Arel::Nodes::TableAlias
current_table.right
else
fail
end
end
これは、arelテーブルを検索するためのベースオブジェクトとして current_scope
を使用します。そのオブジェクトでsource
を呼び出して、 Arel::SelectManager
を取得します。これにより、#left
の現在のテーブルが得られます。そこには2つのオプションがあります。Arel::Table
(エイリアスなし、テーブル名は#name
にあります)があるか、Arel::Nodes::TableAlias
にエイリアスが#right
にあるかのいずれかです。
これで、order
ステートメント(未テスト)でのみ使用する必要があります。
Project.all.includes(:students, :teachers).order("#{current_table_name}.name ASC")
Project.all.includes(:students, :teachers).order("#{current_table_name}.name ASC")
Project.all.includes(:students, :teachers).order("#{current_table_name}.name ASC")
関連する質問: