Ruby-on-rails 在 Rails 中过滤 ActiveRecord 查询

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/936947/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 21:18:28  来源:igfitidea点击:

Filtering ActiveRecord queries in rails

ruby-on-railsrubyactiverecord

提问by user94154

I'm used to Django where you can run multiple filter methods on querysets, ie Item.all.filter(foo="bar").filter(something="else").

我习惯了 Django,您可以在其中对查询集运行多个过滤器方法,即Item.all.filter(foo="bar").filter(something="else").

The however this is not so easy to do in Rails. Item.find(:all, :conditions => ["foo = :foo", { :foo = bar }])returns an array meaning this will not work:

然而,这在 Rails 中并不是那么容易做到的。Item.find(:all, :conditions => ["foo = :foo", { :foo = bar }])返回一个数组,这意味着这将不起作用:

Item.find(:all, :conditions => ["foo = :foo", { :foo = 'bar' }]).find(:all, :conditions => ["something = :something", { :something = 'else' }])

Item.find(:all, :conditions => ["foo = :foo", { :foo = 'bar' }]).find(:all, :conditions => ["something = :something", { :something = 'else' }])

So I figured the best way to "stack" filters is to modify the conditions array and then run the query.

所以我认为“堆叠”过滤器的最佳方法是修改条件数组,然后运行查询。

So I came up with this function:

所以我想出了这个功能:

 def combine(array1,array2)
   conditions = []
   conditions[0] = (array1[0]+" AND "+array2[0]).to_s
   conditions[1] = {}
   conditions[1].merge!(array1[1])
   conditions[1].merge!(array2[1])
   return conditions
 end

Usage:

用法:

array1 = ["foo = :foo", { :foo = 'bar' }] array2 = ["something = :something", { :something = 'else' }] conditions = combine(array1,array2) items = Item.find(:all, :conditions => conditions)

array1 = ["foo = :foo", { :foo = 'bar' }] array2 = ["something = :something", { :something = 'else' }] conditions = combine(array1,array2) items = Item. find(:all, :conditions => 条件)

This has worked pretty well. However I want to be able to combine an arbitrary number of arrays, or basically shorthand for writing:

这工作得很好。但是我希望能够组合任意数量的数组,或者基本上是写的简写:

conditions = combine(combine(array1,array2),array3)

Can anyone help with this? Thanks in advance.

有人能帮忙吗?提前致谢。

回答by Fran?ois Beausoleil

What you want are named scopes:

你想要的是命名范围:

class Item < ActiveRecord::Base
  named_scope :by_author, lambda {|author| {:conditions => {:author_id => author.id}}}
  named_scope :since, lambda {|timestamp| {:conditions => {:created_at => (timestamp .. Time.now.utc)}}}
  named_scope :archived, :conditions => "archived_at IS NOT NULL"
  named_scope :active, :conditions => {:archived_at => nil}
end

In your controllers, use like this:

在您的控制器中,像这样使用:

class ItemsController < ApplicationController
  def index
    @items = Item.by_author(current_user).since(2.weeks.ago)
    @items = params[:archived] == "1" ? @items.archived : @items.active
  end
end

The returned object is a proxy and the SQL query will not be run until you actually start doing something real with the collection, such as iterating (for display) or when you call Enumerable methods on the proxy.

返回的对象是一个代理,SQL 查询将不会运行,直到您真正开始对集合执行一些实际操作,例如迭代(用于显示)或在代理上调用 Enumerable 方法时。

回答by klew

I wouldn't do it like you proposed.

我不会像你提议的那样做。

Since find return an array, you can use array methods to filter it, on example:

由于 find 返回一个数组,您可以使用数组方法对其进行过滤,例如:

Item.find(:all).select {|i| i.foo == bar }.select {|i| i.whatever > 23 }...

You can also achive what you want with named scopes.

您还可以使用命名范围来实现您想要的。

回答by andi

You can take a look at Searchlogic.
It makes it easier to use conditions on ActiveRecordsets, and even on Arrays.

你可以看看Searchlogic
它可以更轻松地在ActiveRecord集合上使用条件 ,甚至在Arrays.

Hope it helps.

希望能帮助到你。

回答by workmad3

You can (or at least used to be able to) filter like so in Rails:

您可以(或至少曾经能够)在 Rails 中像这样过滤:

find(:all, :conditions => { :foo => 'foo', :bar => 'bar' })

where :foo and :bar are field names in the active record. Seems like all you need to do is pass in a hash of :field_name => value pairs.

其中 :foo 和 :bar 是活动记录中的字段名称。似乎您需要做的就是传入 :field_name => 值对的哈希值。