Фильтрация запросов ActiveRecord в рельсах
Я использую Django, где вы можете запускать несколько методов фильтрации в запросах, т.е. Item.all.filter(foo="bar").filter(something="else")
.
Однако это не так просто сделать в Rails. Item.find(:all, :conditions => ["foo = :foo", { :foo = bar }])
возвращает массив, который не будет работать:
Item.find(:all, :conditions => ["foo = :foo", { :foo = 'bar' }]).find(:all, :conditions => ["something = :something", { :something = 'else' }])
Итак, я решил, что лучший способ "стека" фильтров состоит в том, чтобы изменить массив условий, а затем запустить запрос.
Итак, я придумал эту функцию:
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
Использование:
array1 = [ "foo =: foo", {: foo = 'bar'}]
array2 = [ "something =: something", {: something = 'else'}]
условия = объединение (array1, array2)
items = Item.find(: all,: conditions = > условия)
Это работает очень хорошо. Однако я хочу иметь возможность комбинировать произвольное количество массивов или в основном сокращать для записи:
conditions = combine(combine(array1,array2),array3)
Может ли кто-нибудь помочь с этим? Спасибо заранее.
Ответы
Ответ 1
То, что вы хотите, называется областью:
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
В ваших контроллерах используйте следующее:
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
Возвращаемый объект является прокси-сервером, и SQL-запрос не будет выполняться до тех пор, пока вы фактически не начнете делать что-то реальное с коллекцией, например, итерацию (для отображения) или когда вы вызываете методы Enumerable на прокси-сервере.
Ответ 2
Я бы не сделал этого, как вы предлагали.
Так как find возвращает массив, вы можете использовать методы массива для его фильтрации, например:
Item.find(:all).select {|i| i.foo == bar }.select {|i| i.whatever > 23 }...
Вы также можете добиться того, что хотите с помощью названных областей.
Ответ 3
Я думаю, что вы хотите: Именованный масштаб
Ответ 4
Вы можете посмотреть Searchlogic.
Это облегчает использование условий для
ActiveRecord
и даже на Arrays
.
Надеюсь, что это поможет.
Ответ 5
Вы можете (или, по крайней мере, использовать, чтобы иметь возможность) фильтровать так в Rails:
find(:all, :conditions => { :foo => 'foo', :bar => 'bar' })
где: foo и: bar - имена полей в активной записи. Похоже, все, что вам нужно сделать, это передать хэш из следующих полей: field_name = > value.