我正试图有条件地建立一个模型列表。即。
@items = []
if some_condition
@items << MyModel.where(...)
end
if another_condition
@items << MyModel.where(...)
end
...
这不起作用。它实际上会构建一个正确对象的数组,但是当我访问数组中项目的字段和关系时,它们“找不到”。我尝试了其他一些内容,例如@items = MyModel.none
和@items = {}
以及.merge
,但都没有效果。我似乎无法弄清楚这一点。
有条件地建立像这样的集合的最佳方法是什么?
更新我希望能够维护Relation
,以便我可以继续使用.where
,.first
和其余的Relation
来查询它{{1}}方法。
答案 0 :(得分:5)
<<
会将一个项目附加到数组中,因此查询将不会被运行,而是作为ActiveRecord::Relation
附加,如果您使用all
,则最终会数组数组。您应该使用concat
附加整个集合(+=
也可以工作,但如果您的查询返回大量记录,则会实例化影响性能的不必要的临时数组):
@items = []
if some_condition
@items.concat(MyModel.where(...))
end
if another_condition
@items.concat(MyModel.where(...))
end
答案 1 :(得分:3)
您的串联方法将导致多个数据库查询,并且不会是可链接的,这通常是分页,范围,分组和排序所必需的。
我会收集您的条件并在最后结合。看起来您的条件实际上是OR类型查询,而不是更容易链接的AND类型查询。
请执行以下操作:
@queries = []
if some_condition
# Relation condition
@queries << MyModel.where(...)
end
if another_condition
# another Relation condition
@queries << MyModel.where(...)
end
if and_another_condition
# Hash equality and IN conditions
@queries << { attr1: 'foo', attr2: [1,2,3] }
end
if yet_another_condition
# string condition with argument
@queries << ['attr LIKE ? ', arg]
end
@items = MyModel.any_of(*queries).order(...).page(...).per(...)
神奇的是一个漂亮的自定义AR扩展方法any_of?
,用于使用Arel组合OR类型查询。它可以使用Relations,String条件,Hash条件或Arrays来splatting到where()子句。
# put in config/initializers/ar_any_of.rb or in lib/xxxx
class ActiveRecord::Base
def self.any_of(*queries)
where(
queries.map { |query|
query = where(query) if [String, Hash].any? { |type| query.kind_of? type }
query = where(*query) if query.kind_of? Array
query.arel.constraints.reduce(:and)
}.reduce(:or)
)
end
end
可以使用以下各种条件生成单个SQL:
Country.any_of(
Country.where(alpha2: 'AU'),
{ alpha2: ['NZ', 'UK'] },
['alpha2 LIKE ?', 'U%']).to_sql
# => "SELECT \"countries\".* FROM \"countries\" WHERE (((\"countries\".\"alpha2\" = 'AU' OR \"countries\".\"alpha2\" IN ('NZ', 'AD')) OR (alpha2 LIKE 'U%')))"
答案 2 :(得分:-1)
我认为答案很简单。
您可以将收藏集初始化为anonymous scope
@items = MyModel.scoped
这是一个ActiveRecord :: Relation。
**请注意,{4}已弃用scoped
但all
执行相同的操作http://blog.remarkablelabs.com/2012/12/what-s-new-in-active-record-rails-4-countdown-to-2013,因此我们的示例将是
@items = MyModel.all
在此之后,链接额外条件(按条件)应该非常简单:
@items = @items.where(owner: me) if me.present?
@items = @items.group(:attribute_1) if show_groups