Подтвердить что ты не робот

Фильтрация запросов 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)

Может ли кто-нибудь помочь с этим? Спасибо заранее.

4b9b3361

Ответ 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 }...

Вы также можете добиться того, что хотите с помощью названных областей.

Ответ 4

Вы можете посмотреть Searchlogic.
Это облегчает использование условий для ActiveRecord и даже на Arrays.

Надеюсь, что это поможет.

Ответ 5

Вы можете (или, по крайней мере, использовать, чтобы иметь возможность) фильтровать так в Rails:

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

где: foo и: bar - имена полей в активной записи. Похоже, все, что вам нужно сделать, это передать хэш из следующих полей: field_name = > value.