2009-06-01 4 views
21

Я привык к Django, где вы можете запускать несколько методов фильтрации на запросах, то есть Item.all.filter(foo="bar").filter(something="else").Фильтрация запросов ActiveRecord в рельсах

Однако это не так-то просто сделать в 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 =}] array2 = [ "что-то =: что-то», {: что-то = 'Else'}] условия = сочетающие (array1, array2) элементы = Item.find (: все,: условия => условия)

Это работает очень хорошо. Однако я хочу, чтобы иметь возможность объединить произвольное количество массивов, или в основном обсчитывать для записи:

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

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

ответ

35

Что вы хотите названы прицелы:

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 на прокси.

+0

Да, это именно то, что я хочу. Я наблюдал за скринкастом, и это имело для меня общий смысл. Но как только я активировал код, я получил сообщение об ошибке, указав, что named scope - это неопределенный метод. Затем я заметил, что я работал с Rails 1.8, поэтому я обновил рельсы до 2.3.что-то и по-прежнему получаю ту же ошибку .... я знал, что имена областей слишком хороши, чтобы быть правдой:/ – user94154

+1

Если вы заморозили Rails, то ваш код по-прежнему использует предыдущую версию Rails. Rails 1.8 никогда не существовал, поэтому вы должны понимать Ruby 1.8. rails -v - это команда, которая расскажет вам, какая версия Rails существует в командной строке. script/about расскажет вам больше о среде вашего приложения. –

+0

колоритный рубиновый скрипт/о не был признан. Что означает замороженное значение в терминах Rails? – user94154

1

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

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

1

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

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

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

+0

Это сработало для меня (я на 1.8.7) – John

6

Я бы так не сделал, как вы предлагали.

Поскольку найти возвращает массив, вы можете использовать методы массива для фильтрации его на примере:

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

Вы также можете achive то, что вы хотите с именованными областями.

+1

Именованные области - это гораздо лучший способ сделать это, и это дает вам легко используемые методы, которые вы можете использовать. – nitecoder

+1

@railsninja: Я согласен, но перед тем, как вы его используете, вы должны определить именованный диапазон. Если вы хотите что-то сделать только один раз, проще использовать select. – klew

+2

Неправда. Вы можете делать анонимные области на лету: http://railscasts.com/episodes/112-anonymous-scopes –

Смежные вопросы