Rails 4 - 如何在活动记录查询中为包含()和连接()提供别名
Posted
技术标签:
【中文标题】Rails 4 - 如何在活动记录查询中为包含()和连接()提供别名【英文标题】:Rails 4 - how to give alias names to includes() and joins() in active record querying 【发布时间】:2015-04-20 03:55:51 【问题描述】:我怎样才能给例如一个别名? includes()
?
下面给出:
这里有一些例子:
FIRST CASE(更多 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
自动使用别名 teachers_projects
。如何覆盖它,以便我可以在 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 协会)
如果我在方法includes()
中仅使用:students
(不使用:teachers
),Rails 会为:students
使用STI 基类名称users
(未附加_projects
)的名称别名:
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 别名跟踪器
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
【问题讨论】:
你有没有尝试过类似 Project.joins(:teachers).where...... 如果你得到答案,请通知我,这样我也能看到答案。 您能否提供一个 Gist 以显示模型定义、迁移和一些数据。以便我可以设置并尝试做? @phlegx 谢谢.. 让我们看看我能不能帮你。 :-) @phlegx 你的项目在公共 GitHub 上吗? 【参考方案1】: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
作为参数的 Class 方法中会使其更加整洁和可重用,因为这在控制器中看起来有点混乱。
【讨论】:
【参考方案2】:我将采用另一种方法来解决这个问题:我不会尝试使用 .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 query with alias'd table names(我第一次使用这种方法的地方)。 Join the same table twice with conditions【讨论】:
我在您提到的一个问题中给出了答案。你可以稍微简化一下。current_scope.table
与 current_scope.arel.source.left
相同(可能不在 Rails "Arel syntax",则不必获取裸表名称。例如。像这样使用它:at = current_scope.table
,然后 at[:the_column_name].asc
和 Arel
为你做所有事情。 (也许你必须添加一个.to_sql
,但我认为 Rails 会为你处理)以上是关于Rails 4 - 如何在活动记录查询中为包含()和连接()提供别名的主要内容,如果未能解决你的问题,请参考以下文章
在 Rails 中通过其 belongs_to 关系查询记录