2009-06-01 32 views
21

Tôi đã quen với Django, nơi bạn có thể chạy nhiều phương pháp lọc trên queryset, tức là Item.all.filter(foo="bar").filter(something="else").Lọc truy vấn ActiveRecord trong đường ray

Tuy nhiên điều này không dễ dàng thực hiện trong Rails. Item.find(:all, :conditions => ["foo = :foo", { :foo = bar }]) lợi nhuận một mảng có nghĩa là điều này sẽ không làm việc:

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

Vì vậy, tôi đã tìm cách tốt nhất để "ngăn xếp" bộ lọc là để sửa đổi các mảng điều kiện và sau đó chạy truy vấn.

Vì vậy, tôi đã đưa ra chức năng này:

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 

Cách sử dụng:

array1 = [ "foo =: ​​foo", {: foo = 'bar'}] array2 = [ "một cái gì đó =: something ", {: something = 'else'}] điều kiện = kết hợp (mảng 1, mảng2) mục = Item.find (: tất cả,: điều kiện => điều kiện)

Điều này đã hoạt động khá tốt. Tuy nhiên, tôi muốn có thể kết hợp một số mảng tùy ý hoặc viết tắt về cơ bản để viết:

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

Bất kỳ ai có thể trợ giúp việc này? Cảm ơn trước.

Trả lời

35

phạm vi những gì bạn muốn được đặt tên:

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 

Trong điều khiển của bạn, sử dụng như thế này:

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 

Đối tượng quay trở lại là một proxy và truy vấn SQL sẽ không được chạy cho đến khi bạn thực sự bắt đầu làm một cái gì đó thực sự với bộ sưu tập, chẳng hạn như iterating (để hiển thị) hoặc khi bạn gọi Enumerable phương pháp trên proxy.

+0

Đúng, đó là chính xác những gì tôi muốn. Tôi đã xem màn hình và nó có ý nghĩa với tôi. Nhưng ngay khi tôi kích hoạt mã, tôi nhận được một lỗi nói rằng phạm vi được đặt tên là một phương thức không xác định. Sau đó, tôi nhận thấy rằng tôi đã làm việc với Rails 1.8, vì vậy tôi đá quý cập nhật đường ray để 2.3.something và vẫn có cùng một lỗi .... ugh, tôi biết phạm vi được đặt tên là quá tốt là đúng:/ – user94154

+1

Nếu bạn đóng băng Rails, sau đó mã của bạn vẫn đang sử dụng phiên bản trước của Rails. Rails 1.8 chưa từng tồn tại, vì vậy bạn phải có nghĩa là Ruby 1.8. rails -v là một lệnh sẽ cho bạn biết phiên bản Rails nào tồn tại ở dòng lệnh. script/about sẽ cho bạn biết thêm về môi trường của ứng dụng của bạn. –

+0

cũng ruby ​​script/về không được công nhận. Những gì hiện đông lạnh có nghĩa là về Rails? – user94154

1

Bạn có thể xem Searchlogic.
Điều này giúp dễ dàng sử dụng các điều kiện trên ActiveRecord bộ và thậm chí trên Arrays.

Hy vọng điều đó sẽ hữu ích.

4

Tôi nghĩ rằng những gì bạn muốn đây là: Named Scope

1

Bạn có thể (hoặc ít nhất là sử dụng để có thể) lọc như vậy trong Rails:

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

nơi: foo và: thanh là lĩnh vực tên trong hồ sơ hoạt động. Có vẻ như tất cả những gì bạn cần làm là chuyển một giá trị băm: field_name => các cặp giá trị.

+0

Điều này phù hợp với tôi (Tôi đang ở mức 1,8.7) – John

6

Tôi sẽ không làm như bạn đã đề xuất.

Kể từ khi tìm thấy trả về một mảng, bạn có thể sử dụng phương pháp mảng để lọc nó, trên ví dụ:

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

Bạn cũng có thể đạt được những gì bạn muốn với phạm vi được đặt tên.

+1

Phạm vi được đặt tên là cách tốt hơn để thực hiện việc này và nó mang lại cho bạn các phương pháp có thể sử dụng dễ dàng có thể sử dụng được. – nitecoder

+1

@railsninja: Tôi đồng ý, nhưng bạn phải xác định phạm vi được đặt tên trước khi sử dụng. Nếu bạn muốn làm điều gì đó chỉ một lần, nó dễ sử dụng hơn. – klew

+2

Không đúng sự thật. Bạn có thể thực hiện các phạm vi ẩn danh khi đang bay: http://railscasts.com/episodes/112-anonymous-scopes –

Các vấn đề liên quan