SlideShare una empresa de Scribd logo
1 de 18
Descargar para leer sin conexión
Model.search
    Tse-Ching Ho
     2010-04-25
Ruby Conf Taiwan 2010
ActiveRecord
ActiveRecord v.s. Arel
module 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
 end
end
module 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
 end
end
Scope with Arel
class 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))
 }
end
Product.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)
AREL
Match => LIKE

NotMatch => NOT LIKE
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')
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
Rails 2.3 => Search Logic

Rails 3 => Search Logic
Write Your Own
Search Method !!!
Meta Search
http://github.com/ernie/meta_search
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)
 end
end
ActiveRecord::Base.send :include, MetaSearch::Searches::ActiveRecord


               Product.search('name_not_like' => 'Ruby')
MetaSearch::Builder
module 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                                      name_not_like=
 end
end
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.first
     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
MetaSearch::Where
MetaSearch::Where.add(['not_like', 'not_contain', 'notmatches', {
    :types => [:string, :text, :binary],
    :condition => :notmatches,           Arel:: Attribute#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
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
About Me


  Tse-Ching Ho
http://github.com/tsechingho



   http://grassbrook.com
END

Más contenido relacionado

La actualidad más candente

Ruby Metaprogramming
Ruby MetaprogrammingRuby Metaprogramming
Ruby Metaprogramming
Nando Vieira
 
Scala ActiveRecord
Scala ActiveRecordScala ActiveRecord
Scala ActiveRecord
scalaconfjp
 
ERRest: the Basics
ERRest: the BasicsERRest: the Basics
ERRest: the Basics
WO Community
 

La actualidad más candente (20)

ALPHA Script - XML Model
ALPHA Script - XML ModelALPHA Script - XML Model
ALPHA Script - XML Model
 
Introduction to PHP Lecture 1
Introduction to PHP Lecture 1Introduction to PHP Lecture 1
Introduction to PHP Lecture 1
 
Ruby Metaprogramming
Ruby MetaprogrammingRuby Metaprogramming
Ruby Metaprogramming
 
Advanced Django
Advanced DjangoAdvanced Django
Advanced Django
 
Learn You a Functional JavaScript for Great Good
Learn You a Functional JavaScript for Great GoodLearn You a Functional JavaScript for Great Good
Learn You a Functional JavaScript for Great Good
 
Art of Javascript
Art of JavascriptArt of Javascript
Art of Javascript
 
Jsp And Jdbc
Jsp And JdbcJsp And Jdbc
Jsp And Jdbc
 
JavaScript - Chapter 6 - Basic Functions
 JavaScript - Chapter 6 - Basic Functions JavaScript - Chapter 6 - Basic Functions
JavaScript - Chapter 6 - Basic Functions
 
Types End-to-End @ samsara
Types End-to-End @ samsaraTypes End-to-End @ samsara
Types End-to-End @ samsara
 
Omnisearch in AEM 6.2 - Search All the Things
Omnisearch in AEM 6.2 - Search All the ThingsOmnisearch in AEM 6.2 - Search All the Things
Omnisearch in AEM 6.2 - Search All the Things
 
Workshop 8: Templating: Handlebars, DustJS
Workshop 8: Templating: Handlebars, DustJSWorkshop 8: Templating: Handlebars, DustJS
Workshop 8: Templating: Handlebars, DustJS
 
Metaprogramming
MetaprogrammingMetaprogramming
Metaprogramming
 
Scala ActiveRecord
Scala ActiveRecordScala ActiveRecord
Scala ActiveRecord
 
jQuery PPT
jQuery PPTjQuery PPT
jQuery PPT
 
Jquery 4
Jquery 4Jquery 4
Jquery 4
 
JavaScript Basics and Best Practices - CC FE & UX
JavaScript Basics and Best Practices - CC FE & UXJavaScript Basics and Best Practices - CC FE & UX
JavaScript Basics and Best Practices - CC FE & UX
 
Fundamental JavaScript [UTC, March 2014]
Fundamental JavaScript [UTC, March 2014]Fundamental JavaScript [UTC, March 2014]
Fundamental JavaScript [UTC, March 2014]
 
PHP array 2
PHP array 2PHP array 2
PHP array 2
 
Activator and Reactive at Play NYC meetup
Activator and Reactive at Play NYC meetupActivator and Reactive at Play NYC meetup
Activator and Reactive at Play NYC meetup
 
ERRest: the Basics
ERRest: the BasicsERRest: the Basics
ERRest: the Basics
 

Similar a model.search: customize your own search logic

Metaprogramovanie #1
Metaprogramovanie #1Metaprogramovanie #1
Metaprogramovanie #1
Jano Suchal
 
Documenting from the Trenches
Documenting from the TrenchesDocumenting from the Trenches
Documenting from the Trenches
Xavier Noria
 

Similar a model.search: customize your own search logic (20)

Metaprogramovanie #1
Metaprogramovanie #1Metaprogramovanie #1
Metaprogramovanie #1
 
Template rendering in rails
Template rendering in rails Template rendering in rails
Template rendering in rails
 
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em RubyTDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em Ruby
 
Documenting from the Trenches
Documenting from the TrenchesDocumenting from the Trenches
Documenting from the Trenches
 
Dsl
DslDsl
Dsl
 
Intro to Rails 4
Intro to Rails 4Intro to Rails 4
Intro to Rails 4
 
Elegant APIs
Elegant APIsElegant APIs
Elegant APIs
 
Ruby/Rails
Ruby/RailsRuby/Rails
Ruby/Rails
 
Rails on Oracle 2011
Rails on Oracle 2011Rails on Oracle 2011
Rails on Oracle 2011
 
All I Need to Know I Learned by Writing My Own Web Framework
All I Need to Know I Learned by Writing My Own Web FrameworkAll I Need to Know I Learned by Writing My Own Web Framework
All I Need to Know I Learned by Writing My Own Web Framework
 
Rails 3 hints
Rails 3 hintsRails 3 hints
Rails 3 hints
 
Ruby on Rails Intro
Ruby on Rails IntroRuby on Rails Intro
Ruby on Rails Intro
 
jQuery and Rails: Best Friends Forever
jQuery and Rails: Best Friends ForeverjQuery and Rails: Best Friends Forever
jQuery and Rails: Best Friends Forever
 
Django design-patterns
Django design-patternsDjango design-patterns
Django design-patterns
 
How To Test Everything
How To Test EverythingHow To Test Everything
How To Test Everything
 
Fewd week6 slides
Fewd week6 slidesFewd week6 slides
Fewd week6 slides
 
Oracle adapters for Ruby ORMs
Oracle adapters for Ruby ORMsOracle adapters for Ruby ORMs
Oracle adapters for Ruby ORMs
 
Getting started with Rails (2), Season 2
Getting started with Rails (2), Season 2Getting started with Rails (2), Season 2
Getting started with Rails (2), Season 2
 
Attributes Unwrapped: Lessons under the surface of active record
Attributes Unwrapped: Lessons under the surface of active recordAttributes Unwrapped: Lessons under the surface of active record
Attributes Unwrapped: Lessons under the surface of active record
 
Rails Plugin Development 101 (...and some...)
Rails Plugin Development 101 (...and some...)Rails Plugin Development 101 (...and some...)
Rails Plugin Development 101 (...and some...)
 

Más de Tse-Ching Ho (9)

20150516 modern web_conf_tw
20150516 modern web_conf_tw20150516 modern web_conf_tw
20150516 modern web_conf_tw
 
Ruby on bioinformatics
Ruby on bioinformaticsRuby on bioinformatics
Ruby on bioinformatics
 
Webconf2013
Webconf2013Webconf2013
Webconf2013
 
Ajax nested form and ajax upload in rails
Ajax nested form and ajax upload in railsAjax nested form and ajax upload in rails
Ajax nested form and ajax upload in rails
 
mongodb-introduction
mongodb-introductionmongodb-introduction
mongodb-introduction
 
devise tutorial - 2011 rubyconf taiwan
devise tutorial - 2011 rubyconf taiwandevise tutorial - 2011 rubyconf taiwan
devise tutorial - 2011 rubyconf taiwan
 
Rails-3-app-auto-generator-20100817
Rails-3-app-auto-generator-20100817Rails-3-app-auto-generator-20100817
Rails-3-app-auto-generator-20100817
 
The Power of Rails 2.3 Engines & Templates
The Power of Rails 2.3 Engines & TemplatesThe Power of Rails 2.3 Engines & Templates
The Power of Rails 2.3 Engines & Templates
 
ruby e-commerce
ruby e-commerceruby e-commerce
ruby e-commerce
 

Último

Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
vu2urc
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and Myths
Joaquim Jorge
 

Último (20)

Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed texts
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
 
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day Presentation
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘
 
Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CV
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
Advantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your BusinessAdvantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your Business
 
HTML Injection Attacks: Impact and Mitigation Strategies
HTML Injection Attacks: Impact and Mitigation StrategiesHTML Injection Attacks: Impact and Mitigation Strategies
HTML Injection Attacks: Impact and Mitigation Strategies
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a Fresher
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century education
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and Myths
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
 

model.search: customize your own search logic

  • 1. Model.search Tse-Ching Ho 2010-04-25 Ruby Conf Taiwan 2010
  • 3. ActiveRecord v.s. Arel module 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 end end module 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 end end
  • 4. Scope with Arel class 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)) } end Product.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)
  • 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
  • 9. Rails 2.3 => Search Logic Rails 3 => Search Logic
  • 10. Write Your Own Search Method !!!
  • 12. 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) end end ActiveRecord::Base.send :include, MetaSearch::Searches::ActiveRecord Product.search('name_not_like' => 'Ruby')
  • 13. MetaSearch::Builder module 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 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.first 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
  • 15. MetaSearch::Where MetaSearch::Where.add(['not_like', 'not_contain', 'notmatches', { :types => [:string, :text, :binary], :condition => :notmatches, Arel:: Attribute#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
  • 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
  • 18. END