ruby-on-rails – 带有别名表名的ActiveRecord查询
使用包含范围的模型关注点,知道嵌套和/或自引用查询的最佳方法是什么?
在我的一个问题中,我的范围与以下类似: 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”=“公司”.“id” 和 INNER JOIN“company_users”ON“users”.“id”=“company_users”.“user_id”WHERE“company_users”.“company_id”= $2 这里的问题是self.table_name不再引用查询中的表名.这导致舌头在脸颊暗示:提示:也许你的意思是引用表别名“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 并更新范围以反映: lower_bound_column.eq(无).或者(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,ActiveRecord和Rails问题的来源(似乎这不是新的),我能够找到访问当前arel_table对象的方法,如果正在使用它们的table_aliases,执行时的当前范围.
这使得可以知道范围是否将在具有别名的表名的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 正如您所看到的,我使用 使用该table_name,您可以在您的范围内恢复为#{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) } 在我看来,这个current_table_name方法对AR / Arel公共API有用,因此可以跨版本升级进行维护.你怎么看? 如果你有兴趣,这里有一些我在路上使用的参考: >一个similar question on SO,回答了大量的代码,你可以使用而不是你美丽而简洁的能力. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |