gpt4 book ai didi

ruby-on-rails - 具有别名表名的 ActiveRecord 查询

转载 作者:行者123 更新时间:2023-12-03 16:43:31 24 4
gpt4 key购买 nike

使用包括范围的模型关注点,知道嵌套和/或自引用查询可能是编写这些关注点的最佳方式是什么?

在我的担忧之一中,我的范围类似于:

scope :current, ->(as_at = Time.now) { current_and_expired(as_at).current_and_future(as_at) }
scope :current_and_future, ->(as_at = Time.now) { where("#{upper_bound_column} IS NULL OR #{upper_bound_column} >= ?", as_at) }
scope :current_and_expired, ->(as_at = Time.now) { where("#{lower_bound_column} IS NULL OR #{lower_bound_column} <= ?", as_at) }

def self.lower_bound_column
lower_bound_field
end
def self.upper_bound_column
upper_bound_field
end

并通过 has_many 引用,例如: has_many :company_users, -> { current }
如果进行 ActiveRecord 查询,该查询引用了包含该关注点的几个模型,则会导致“不明确的列名”异常,这是有意义的。

为了帮助克服这个问题,我将列名辅助方法更改为现在
def self.lower_bound_column
"#{self.table_name}.#{lower_bound_field}"
end
def self.upper_bound_column
"#{self.table_name}.#{upper_bound_field}"
end

效果很好,直到您需要自引用查询。 Arel 通过在生成的 SQL 中为表名设置别名来帮助缓解这些问题,例如:
LEFT OUTER JOIN "company_users" "company_users_companies" ON "company_users_companies"."company_id" = "companies"."id"

INNER JOIN "company_users" ON "users"."id" = "company_users"."user_id" WHERE "company_users"."company_id" = $2
这里的问题是 self.table_name不再引用查询中的表名。这导致舌头在脸颊提示: HINT: Perhaps you meant to reference the table alias "company_users_companies"
为了将这些查询迁移到 Arel,我将列名辅助方法更改为:
def self.lower_bound_column
self.class.arel_table[lower_bound_field.to_sym]
end
def self.upper_bound_column
self.class.arel_table[upper_bound_field.to_sym]
end

并更新了范围以反射(reflect):
lower_bound_column.eq(nil).or(lower_bound_column.lteq(as_at))
但这只是将问题移植到 self.class.arel_table无论查询如何,都将始终相同。

我想我的问题是,如何创建可用于自引用查询的范围,这需要 <= 等运算符和 >= ?

编辑

我创建了一个基本应用程序来帮助展示这个问题。
git clone git@github.com:fattymiller/expirable_test.git
cd expirable_test
createdb expirable_test-development
bundle install
rake db:migrate
rake db:seed
rails s

调查结果和假设
  • 在 sqlite3 中工作,而不是 Postgres。很可能是因为 Postgres 强制执行 SQL 中的查询顺序?
  • 最佳答案

    好,好,好。在查看了 Arel 的源代码之后, , ActiveRecordRails问题(似乎这不是新问题),我能够找到访问当前 arel_table 的方法对象,及其 table_aliases如果正在使用它们,则在 current 内执行时的范围。

    这使得知道范围是否将在 JOIN 中使用成为可能。具有别名的表名,或者另一方面,如果可以在真实表名上使用范围。

    我刚刚将此方法添加到您的Expirable忧虑:

    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 表的基础对象,而不是之前尝试使用 self.class.arel_table甚至 relation.arel_table ,正如您所说,无论在何处使用范围,它都保持不变。我只是调用 source在该对象上获得 Arel::SelectManager 这反过来会给你 #left上的当前表.目前有两个选择:你有一个 Arel::Table (没有别名,表名在 #name 上)或者你有一个 Arel::Nodes::TableAlias#right 上有别名.

    使用该表名,您可以恢复到第一次尝试 #{current_table_name}.#{lower_bound_field}。和 #{current_table_name}.#{upper_bound_field}在您的范围内:
    def self.lower_bound_column
    "#{current_table_name}.#{lower_bound_field}"
    end

    def self.upper_bound_column
    "#{current_table_name}.#{upper_bound_field}"
    end

    scope :current_and_future, ->(as_at = Time.now) { where("#{upper_bound_column} IS NULL OR #{upper_bound_column} >= ?", as_at) }
    scope :current_and_expired, ->(as_at = Time.now) { where("#{lower_bound_column} IS NULL OR #{lower_bound_column} <= ?", as_at) }

    这个 current_table_name在我看来,方法在 AR/Arel 公共(public) API 上很有用,因此可以在版本升级之间进行维护。你怎么看?

    如果您有兴趣,以下是我在路上使用的一些引用资料:
  • 一个 similar question on SO ,用大量代码回答,你可以用它来代替你美丽而简洁的能力。
  • 这个Rails issue这个other one .
  • the commit on your test app在 github 上让测试变得绿色!
  • 关于ruby-on-rails - 具有别名表名的 ActiveRecord 查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28685149/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com