18
Model.search Tse-Ching Ho 2010-04-25 Ruby Conf Taiwan 2010

model.search: customize your own search logic

Embed Size (px)

DESCRIPTION

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.

Citation preview

Page 1: model.search: customize your own search logic

Model.searchTse-Ching Ho2010-04-25

Ruby Conf Taiwan 2010

Page 2: model.search: customize your own search logic

ActiveRecord

Page 3: model.search: customize your own search logic

ActiveRecord v.s. Arelmodule ActiveRecord class Base class < self def unscoped @unscoped ||= Relation.new(self, arel_table) finder_needs_type_condition? ? @unscoped.where(type_condition) : @unscoped end def arel_table @arel_table ||= Arel::Table.new(table_name, :engine => arel_engine) end end endendmodule ActiveRecord::NamedScope::ClassMethods def scoped(options = {}, &block) if options.present? relation = scoped.apply_finder_options(options) block_given? ? relation.extending(Module.new(&block)) : relation else current_scoped_methods ? unscoped.merge(current_scoped_methods) : unscoped.clone end endend

Page 4: model.search: customize your own search logic

Scope with Arelclass Product < ActiveRecord::Base scope :name_like, lambda { |param| where(self.arel_table[:name].matches("%#{param}%")) } scope :attr_like, lambda { |attr, param| where(self.arel_table[attr].matches("%#{param}%")) } scope :attr_gt, lambda { |attr, param| where(self.arel_table[attr].gt(param)) }endProduct.name_like('Ruby')Product.attr_like(:name, 'Ruby') SELECT "products".* FROM "products" WHERE ("products"."name" LIKE '%Ruby%')Product.attr_gt(:price, 100) SELECT "products".* FROM "products" WHERE ("products"."price" > 100)

Page 5: model.search: customize your own search logic

AREL

Page 6: model.search: customize your own search logic

Match => LIKE

NotMatch => NOT LIKE

Page 7: model.search: customize your own search logic

NotMatch ?products = Product.scopedputs products.where(products.table[:name].matches('%Ruby%')).to_sql SELECT "products".* FROM "products" WHERE ("products"."name" LIKE '%Ruby%')

products = Product.scopedputs products.where(%Q{"products"."name" NOT LIKE '%Ruby%'}).to_sqlputs products.where(%Q{"products"."name" NOT LIKE ?}, '%Ruby%').to_sql SELECT "products".* FROM "products" WHERE ("products"."name" NOT LIKE '%Ruby%')

products = Product.scopedproducts.where(products.table[:name].notmatches('%Ruby%'))

products = Product.searchproducts.name_not_like = 'Ruby'

products = Product.search('name_not_like' => 'Ruby')

Page 8: model.search: customize your own search logic

NotMatch !require 'arel'# lib/arel/algebra/predicates.rbmodule Arel::Predicates class NotMatch < Binary; endend# lib/arel/algebra/attributes/attribute.rbmodule Arel class Attribute def notmatches(regexp); Predicates::NotMatch.new(self, regexp) end endend# lib/arel/engines/sql/predicates.rbmodule Arel::Predicates class NotMatch < Binary def predicate_sql; 'NOT LIKE' end endend# lib/arel/engines/memory/predicates.rbmodule Arel::Predicates class NotMatch < Binary def operator; :"!~" end endend

Page 9: model.search: customize your own search logic

Rails 2.3 => Search Logic

Rails 3 => Search Logic

Page 10: model.search: customize your own search logic

Write Your Own Search Method !!!

Page 11: model.search: customize your own search logic

Meta Search

http://github.com/ernie/meta_search

Page 12: model.search: customize your own search logic

MetaSearch::Searches::Base

module MetaSearch::Searches::Base def search(opts = {}) search_options = opts.delete(:search_options) || {} builder = MetaSearch::Builder.new(self, search_options) builder.build(opts) endendActiveRecord::Base.send :include, MetaSearch::Searches::ActiveRecord

Product.search('name_not_like' => 'Ruby')

Page 13: model.search: customize your own search logic

MetaSearch::Buildermodule MetaSearch class Builder attr_reader :base, :relation, :join_dependency delegate :joins, :includes, :all, :count, :to_sql, :paginate, :find_each, :first, :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 endend

name_not_like=

Page 14: model.search: customize your own search logic

MetaSearch::Buildermodule MetaSearch 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.first build_where_method(condition, Where.new(condition)) self.send(method_id, *args) else super end end endend

name_not_like=

@relation.where(products.table[:name].notmatches('%Ruby%')

Page 15: model.search: customize your own search logic

MetaSearch::WhereMetaSearch::Where.add(['not_like', 'not_contain', 'notmatches', { :types => [:string, :text, :binary], :condition => :notmatches, :formatter => '"%#{param}%"'}])@@wheres['not_like'] = { :name => 'not_like', :aliases => ['not_contain', 'notmatches'], :types => [:string, :text, :binary], :condition => :notmatches, :formatter => Proc.new {|param| eval '"%#{param}%"'}, :validator => Proc.new {|param| !param.blank?}, :splat_param => false}#=> Where.new(@@wheres['not_like'])

Where.new('not_like') == Where.get('not_like') # if new with string

Arel:: Attribute#notmatches

Page 16: model.search: customize your own search logic

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/265308http://github.com/ernie/meta_where

Page 17: model.search: customize your own search logic

About Me

Tse-Ching Ho 何澤清

http://github.com/tsechingho

禾川資訊

http://grassbrook.com

Page 18: model.search: customize your own search logic

END