Rails 4 - 如何在活动记录查询中为 include() 和 joins() 指定别名



我怎样才能给出一个别名,例如 includes() ?下面给出:

  • 用户:活动记录模型
  • 学生:活动记录模型,继承自用户 (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 在 SQL 中自动使用别名teachers_projects: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')

第二例(一个性传播感染协会(

如果我在方法 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)

轨道别名跟踪器

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

我将采取另一种方法来解决这个问题:我不会尝试使用 .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,别名在其#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")

相关问题:

  • 使用别名表名的 ActiveRecord 查询(我第一次使用这种方法的地方(。
  • 使用条件加入同一表两次

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(...)

这样的事情应该可以做到。当然,将其放入一些带有:my_student_table_alias作为参数的类方法中会使其更加整洁和可重用,因为这在控制器中看起来有点混乱。

最新更新