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::TableAliasArel::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查询 (我首先使用此方法)。
  • 根据条件加入同一个表两次