Food.where name: 'Peanut butter' # SELECT "foods".* FROM "foods" WHERE "foods"."name" = 'Peanut butter' => [#<Food id: 1, name: "Peanut butter">]But what about like-searching by several terms:
class Food < ActiveRecord::Base def self.search *terms conditions = terms.inject([]) { |conditions, word| conditions << "name LIKE ?" }.join(" OR ") where(conditions, *terms) end endand querying:
Food.search "Butter", "Apple" => [ #<Food id: 1, name: "Peanut butter"> #<Food id: 2, name: "Apple juice"> ]works, but is awkward because:
- it deals with raw SQL fragments
- confuses arguments with question marks
- is by far not object oriented
- suffers the lack of syntax check
class Food < ActiveRecord::Base def self.search *terms conditions = terms.map { |term| arel_table[:name].matches("%#{term}%") }.inject(&:or) where(conditions) end endThe ActiveRecord::Core::ClassMethods#arel_table returns an Arel::Table object. It offers access to all model attributes. For a better understanding: it helps to send to_sql to Arel:
Food.arel_table[:name].matches("%Butter%").to_sql => "\"foods\".\"name\" LIKE '%Butter%'"or the entire example conditions:
%w(Butter Apple).map { |term| Food.arel_table[:name].matches("%#{term}%") }.inject(&:or).to_sql => "(\"foods\".\"name\" LIKE '%Butter%' OR \"foods\".\"name\" LIKE '%Apple%')"which is awesome and reveals the power of Arel. No more writing SQL manually required.
It works:
Food.search "Butter", "Apple" => [ #<Food id: 1, name: "Peanut butter"> #<Food id: 2, name: "Apple juice"> ]The entire flexibility of Arel is documented at Arel API.
Further articles of interest:
Supported by Ruby 2.1.1 and Ruby on Rails 4.1.8
Keine Kommentare:
Kommentar veröffentlichen