Rails 4 – 如何在活动记录查询中为别名()和联接()提供别名
如何为例如includes()
提供别名? 以下是:
- 用户:活动记录模型
- 学生:活动记录模型,inheritance自用户(STI)
- 老师:主动记录模型,inheritance自用户(STI)
- 项目:主动记录模型
这里有一些例子:
第一个案例(更多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自动使用别名:teachers
SQL中的:teachers
。 如何覆盖这个,以便我可以在SQL中使用别名teachers
而不是teachers_projects
? :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')
第二个案例(一个STI协会)
如果我只使用:students
方法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
https://github.com/rails/rails/blob/v4.2.0/activerecord/lib/active_record/associations/alias_tracker.rb#L59
测试应用程序
https://gist.github.com/phlegx/add77d24ebc57f211e8b
https://github.com/phlegx/rails_query_alias_names
Arel确实有一个别名方法。
student_alias = Student.arel_table.alias(:my_student_table_alias)
警告:这将要求您使用更多手工制作的Arel并手动进行连接。 如果你不熟悉它们,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(...)
这样的事情应该做到这一点。 当然把它放到一些Class方法中:my_student_table_alias
作为参数会使它更整洁和可重用,因为这在控制器中看起来有点乱。
我将采用另一种方法来解决这个问题:我不会尝试使用.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
这使用current_scope
作为查找arel表的基础对象。 我正在调用该对象的source
来获取一个Arel::SelectManager
,它反过来将为您提供#left
上的当前表。 有两个选项:要么你有一个Arel::Table
(没有别名,表名在#name
),要么你有一个Arel::Nodes::TableAlias
和Arel::Nodes::TableAlias
上的别名。
现在您只需要在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")
相关问题:
- 具有别名表名的ActiveRecord查询 (我首先使用此方法)。
- 根据条件加入同一个表两次