我怎样才能给出一个别名,例如 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
作为参数的类方法中会使其更加整洁和可重用,因为这在控制器中看起来有点混乱。