SlideShare uma empresa Scribd logo
1 de 18
Baixar para ler offline
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

Mais conteúdo relacionado

Mais procurados

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
 

Mais procurados (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
 

Semelhante 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
 

Semelhante 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...)
 

Mais 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

+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
?#DUbAI#??##{{(☎️+971_581248768%)**%*]'#abortion pills for sale in dubai@
 
Architecting Cloud Native Applications
Architecting Cloud Native ApplicationsArchitecting Cloud Native Applications
Architecting Cloud Native Applications
WSO2
 
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Victor Rentea
 

Último (20)

Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
 
Introduction to Multilingual Retrieval Augmented Generation (RAG)
Introduction to Multilingual Retrieval Augmented Generation (RAG)Introduction to Multilingual Retrieval Augmented Generation (RAG)
Introduction to Multilingual Retrieval Augmented Generation (RAG)
 
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
 
DBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor PresentationDBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor Presentation
 
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWEREMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
 
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ..."I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
 
Exploring Multimodal Embeddings with Milvus
Exploring Multimodal Embeddings with MilvusExploring Multimodal Embeddings with Milvus
Exploring Multimodal Embeddings with Milvus
 
DEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
DEV meet-up UiPath Document Understanding May 7 2024 AmsterdamDEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
DEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
 
ICT role in 21st century education and its challenges
ICT role in 21st century education and its challengesICT role in 21st century education and its challenges
ICT role in 21st century education and its challenges
 
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodPolkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
 
Architecting Cloud Native Applications
Architecting Cloud Native ApplicationsArchitecting Cloud Native Applications
Architecting Cloud Native Applications
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024
 
Artificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyArtificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : Uncertainty
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
 
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of Terraform
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
 
WSO2's API Vision: Unifying Control, Empowering Developers
WSO2's API Vision: Unifying Control, Empowering DevelopersWSO2's API Vision: Unifying Control, Empowering Developers
WSO2's API Vision: Unifying Control, Empowering Developers
 
Platformless Horizons for Digital Adaptability
Platformless Horizons for Digital AdaptabilityPlatformless Horizons for Digital Adaptability
Platformless Horizons for Digital Adaptability
 

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