2009-10-29 19 views
2

比方說,我有一個表單,用戶可以搜索名稱以特定name字符串開頭的人,例如「Mi」會找到「Mike」和「Miguel」。我可能會創建一個查找的語句,像這樣:帶綁定變量和可選參數的條件

find(:all, :conditions => ['name LIKE ?', "#{name}%"]) 

假設形式也有兩個可選字段,hair_coloreye_color,可用於進一步篩選結果。忽略查詢的名稱部分,對人的發現語句可以在可選參數任意數量的可能是這樣的:

find(:all, :conditions => { params[:person] })

這對於我的兩個可選參數將表現爲這相當於:

find(:all, :conditions => { :hair_color => hair_color, :eye_color => eye_color })

我想不通的是如何這兩種查詢,其中必填字段,「名稱」適用於「喜歡」條件之上,並且可選hair_coloreye_color合併PARAMET可以添加ers(也可能是其他)來進一步過濾結果。

我當然可以建立一個查詢字符串來做到這一點,但我覺得必須有一個更優雅的「rails方式」。我如何將強制綁定參數與可選參數合併?

回答

4

這是命名作用域的完美使用。

在模型中創建一個名爲範圍:

named_scope :with_name_like, lambda {|name| 
    {:conditions => ['name LIKE ?', "#{name}%"]} 
} 

此時,您可以撥打

Model.with_name_like("Mi").find(:all, :conditions => params[:person]) 

和Rails將合併查詢你。

編輯:代碼克瓦:

如果名稱是可選的,你可以將其省略從你的方法鏈中的命名範圍使用if條件:

unless name.blank? 
    Model.with_name_like("Mi").find(:all, :conditions => params[:person]) 
else 
    Model.find(:all, :conditions => params[:person]) 
end 

或者你可以在命名範圍重新定義做同樣的事。

named_scope :with_name_like, lambda {|name| 
    if name.blank? 
    {} 
    else 
    {:conditions => ['name LIKE ?', "#{name}%"]} 
    end 
} 

更新

這裏是Rails 3版本的最後一個代碼片斷:

scope :with_name_like, lambda {|name| 
    if not name.blank? 
    where('name LIKE ?', "#{name}%") 
    end 
} 
+0

只是好奇。如果指定名稱字符串也是可選的,那麼如何擴展它? – Waseem 2009-10-29 08:22:29

+0

我知道必須有一個很好的乾淨方式來做到這一點。總是有鐵軌:-)謝謝! – SingleShot 2009-10-29 15:32:38

+1

@waseem,我修改瞭解決方案來回答你的問題。 – EmFi 2009-10-29 16:55:59

0

要同時符合克瓦請求,但允許零而不是空白? (這是在的情況下udeful要使用 「@things = Thing.named_like(PARAMS [:名字])」 直接)

named_scope :named_like, lambda do |*args| 
    if (name=args.first) 
    {:conditions => ["name like ?",name]} 
    else 
    {} 
    end 
end 

# or oneliner version: 

named_scope :named_like, lambda{|*args| (name=args.first ? {:conditions => ["name like ?",name]} : {}) } } 

我希望它能幫助