Rails 4 - 如何在活动记录查询中为别名()和联接()提供别名

phl*_*egx 16 activerecord ruby-on-rails arel ruby-on-rails-3 ruby-on-rails-4

我怎样才能给出别名includes()?以下是:

  • 用户:活动记录模型
  • 学生:活动记录模型,继承自用户(STI)
  • 老师:主动记录模型,继承自用户(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
Run Code Online (Sandbox Code Playgroud)

Rails的自动使用别名teachers_projects:teachers在SQL.我怎样才能覆盖这个,以便我可以使用别名teachers而不是teachers_projectsSQL?: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')
Run Code Online (Sandbox Code Playgroud)

第二个案例(一个STI协会)

如果我只使用:students(不:teachers)方法includes(),Rails使用STI基类名称的名称别名users(没有_projects附加):students:

Project.all.includes(:students).order('users.name ASC') # order on students
Run Code Online (Sandbox Code Playgroud)

这个例子失败了:

Project.all.includes(:students).order('students.name ASC')
Project.all.includes(:students).order('students_projects.name ASC')
Run Code Online (Sandbox Code Playgroud)

可能存在类似于:

Project.all.includes(:students).alias(students: :my_alias)
Run Code Online (Sandbox Code Playgroud)

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

dgi*_*rez 3

我将采取另一种方法来解决这个问题:我不会尝试使用方法来控制查询上的别名.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
Run Code Online (Sandbox Code Playgroud)

这用作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")
Run Code Online (Sandbox Code Playgroud)

相关问题: