2013-02-26 36 views
7

Tôi đã gặp phải vấn đề này nhiều lần: Tôi muốn áp dụng phạm vi truy vấn, nhưng chỉ khi tham số được chuyển đến phạm vi không phải là null . Vì vậy,Rails, áp dụng phạm vi hoặc không phụ thuộc vào việc tham số là nil

tags = Tag.where(name: params[:name]) if params[:name] 

Tuy nhiên, có hai vấn đề với điều này. Một là Rails sẽ đánh giá truy vấn ngay lập tức và vì vậy nếu tôi muốn áp dụng nhiều điều kiện hơn cho nó, hãy nói

tags.where(location: params[:place]) if params[:place] 

Nó sẽ truy vấn lại DB. Vấn đề thứ hai là nó không trông rất đẹp, mà tôi đã cố gắng để có được xung quanh với các phương pháp lớp.

class Tag < ActiveRecord::Base 
    def self.name_like this_name 
     if !this_name.blank? 
     where("name ILIKE '%#{this_name}%'") 
     else 
     #what do I put here? `all` does not work 
     end 
    end 
    end 

Tuy nhiên, tôi không thể chỉ đơn giản là chỉ cần đặt all trong đó, vì điều đó đánh giá truy vấn. Có suy nghĩ gì không?

Trả lời

9

Ở đây bạn có thể sử dụng một phạm vi lambda, và sử dụng self gọi self.all:

class Tag < ActiveRecord::Base 

    scope :named_like, (lambda do |name| 
     if name.present? 
     where("name ILIKE ?", "%#{name}%") 
     else 
     scoped # does not apply a where clause 
     end 
    end) 

    end 

này được dùng quá nhiều dòng trong một phạm vi rất cơ bản, đây là phiên bản nén:

class Tab < ActiveRecord::Base 

    scope :named_like, lambda{ |name| self.where("name ILIKE ?", "%#{name}%") if name.present? } 

end 

Ngoài ra:

+0

Aha! Nó hoạt động. Tại sao bạn có thể chuỗi này cùng với các phạm vi khác trong một phạm vi lambda nhưng bạn không thể với các phương thức lớp? Ví dụ, làm một cái gì đó như 'Tag.name_like (" stuff "). Where (...). All' ...... – varatis

+0

Có bạn có thể (Rails 3), phạm vi chuỗi nên có thể theo như phạm vi/phương thức trả về AR :: Quan hệ. (Bạn không cần phải gọi 'tất cả' ở cuối) – MrYoshiji

+0

Vâng và ngoài ra bạn không thể gọi tất cả. Giải pháp này chỉ hoạt động nếu bạn không, trên thực tế. Tôi chỉ chỉnh sửa nó để chấp nhận rằng – varatis

0

Đối với những gì tôi biết (và những gì không lành mạnh ở đây: ActiveRecord::Relation), truy vấn được thực hiện chỉ khi bạn duyệt qua kết quả. Vì vậy, khi bạn viết một cái gì đó như:

tags = Tags.where(name: params[:name]) 
# other stuff here 
tags = tags.where(location: params[:place]) 

Trong đoạn mã này, không có truy vấn nào được thực hiện.

tags.each { # do something } 

Nhưng đúng rồi! Chỉ một lần, tất nhiên.
Ngay từ đầu, thẻ là đối tượng ActiveRecord :: Relation và do đó bạn có thể chuỗi số lượng where bạn thích.

+0

Vâng, tôi nghĩ bạn nói đúng. Vì vậy, tôi có thể giữ mọi thứ như một phương pháp lớp .... Tôi nghĩ rằng ..... http://guides.rubyonrails.org/active_record_querying.html – varatis

+0

Chính xác, nếu bạn cần loại tính năng này ở nhiều nơi, bạn có thể gói nó trong một phương thức lớp của mô hình :) Nhưng tôi nghĩ là tốt hơn nếu bạn chuyển 'param' làm đối số thay vì sử dụng nó trực tiếp. – Iazel

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