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
end
and 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
end
The 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