This is a lightning talk in Rubyconf Taiwan 2010. I talk about the principles of how to customize your own Model.search method for rails 3. Meta search is an implementation for this purpose and also an available replacement of searchlogic for now.
7. NotMatch ?
products = Product.scoped
puts products.where(products.table[:name].matches('%Ruby%')).to_sql
SELECT "products".* FROM "products"
WHERE ("products"."name" LIKE '%Ruby%')
products = Product.scoped
puts products.where(%Q{"products"."name" NOT LIKE '%Ruby%'}).to_sql
puts products.where(%Q{"products"."name" NOT LIKE ?}, '%Ruby%').to_sql
SELECT "products".* FROM "products"
WHERE ("products"."name" NOT LIKE '%Ruby%')
products = Product.scoped
products.where(products.table[:name].notmatches('%Ruby%'))
products = Product.search
products.name_not_like = 'Ruby'
products = Product.search('name_not_like' => 'Ruby')
8. NotMatch !
require 'arel'
# lib/arel/algebra/predicates.rb
module Arel::Predicates
class NotMatch < Binary; end
end
# lib/arel/algebra/attributes/attribute.rb
module Arel
class Attribute
def notmatches(regexp); Predicates::NotMatch.new(self, regexp) end
end
end
# lib/arel/engines/sql/predicates.rb
module Arel::Predicates
class NotMatch < Binary
def predicate_sql; 'NOT LIKE' end
end
end
# lib/arel/engines/memory/predicates.rb
module Arel::Predicates
class NotMatch < Binary
def operator; :"!~" end
end
end
13. MetaSearch::Builder
module MetaSearch
class Builder
attr_reader :base, :relation, :join_dependency
delegate :joins, :includes, :all, :count, :to_sql, :paginate, :ïŹnd_each,
:ïŹrst, :last, :each, :to => :relation
def initialize(base, opts = {})
@base = base
@associations = {}
@join_dependency =
ActiveRecord::Associations::ClassMethods::JoinDependency.new(@base, [],
nil)
@relation = @base.scoped
end
def build(opts)
@relation = @base.scoped
opts.each_pair {|k, v| self.send("#{k}=", v)}
self
end name_not_like=
end
end
14. MetaSearch::Builder
module MetaSearch name_not_like=
class Builder
def method_missing(method_id, *args, &block)
if match = matches_attribute_method(method_id)
condition, attribute, association = match.captures.reverse
build_method(association, attribute, condition)
self.send(preferred_method_name(method_id), *args)
elsif match = matches_where_method(method_id)
condition = match.captures.ïŹrst
build_where_method(condition, Where.new(condition))
self.send(method_id, *args)
else
super @relation.where(products.table[:name]
end .notmatches('%Ruby%')
end
end
end
16. More Possibilities ?
Article.where(:created_at > 100.days.ago, :title =~ 'Hi%').to_sql
SELECT "articles".* FROM "articles"
WHERE ("articles"."created_at" > '2010-01-05 20:11:44.997446')
AND ("articles"."title" LIKE 'Hi%')
http://gist.github.com/265308
http://github.com/ernie/meta_where
17. About Me
Tse-Ching Ho
http://github.com/tsechingho
http://grassbrook.com