Class: SearchApi::Search::Base
- Inherits:
-
Object
- Object
- SearchApi::Search::Base
- Includes:
- Callbacks
- Defined in:
- lib/search_api/search.rb,
lib/search_api.rb
Overview
The SearchApi::Search::Base class is able to encapsulate search parameters for a given model.
In order to search for instances of your model Stuff, you must:
-
ensure Stuff responds to
search_api_bridge
method. This is, by default, the case of ActiveRecord::Base subclasses. -
define a subclass of SearchApi::Search::Base that uses Stuff as a model:
class StuffSearch < SearchApi::Search::Base # search for Stuff model Stuff end
Assuming Stuff is an ActiveRecord::Base subclass, automatic search attributes are defined in StuffSearch. You can immediately use them:
Those two statements are strictly equivalent:
Stuff.find(:all, {:birth_date => Time.now})
Stuff.find(:all, StuffSearch.new(:birth_date => Time.now).)
So far, so good. But that’s not very funky.
You can also define your own search attributes:
class StuffSearch < SearchApi::Search::Base
# search for Stuff
model Stuff
search_accessor :max_age do |search|
{ :conditions => ['birth_date > ?', Time.now - search.max_age.years]}
end
end
This allows you to perform searches on age:
Stuff.find(:all, StuffSearch.new(:max_age => 20).)
You can mix search keys:
Stuff.find(:all, StuffSearch.new(:max_age => 20, :sex => 'M').)
Constant Summary collapse
- VALID_SEARCH_ATTRIBUTE_OPTIONS =
[ :store_as, :default ]
Constants included from Callbacks
Class Method Summary collapse
-
.model(*args) ⇒ Object
Without any argument, returns the model of this SearchApi::Search::Base class.
-
.search_accessor(*args, &block) ⇒ Object
This is how you add search attributes to your SearchApi::Search::Base class.
-
.search_attributes ⇒ Object
Returns an unordered Array of all search attributes defined through search_accessor.
Instance Method Summary collapse
-
#attributes ⇒ Object
Returns a Hash of search attributes.
-
#attributes=(attributes = nil) ⇒ Object
Sets search attributes via a Hash.
-
#find_options ⇒ Object
Returns an object that should be enough to define a model search.
-
#ignore!(search_attribute) ⇒ Object
Ignore given search_attribute.
-
#ignored?(search_attribute) ⇒ Boolean
Returns whether search_attribute is ignored.
-
#initialize(attributes = nil) ⇒ Base
constructor
Initializes a search with a search attributes Hash.
Methods included from Callbacks
append_features, #before_find_options, #find_options_with_callbacks
Constructor Details
#initialize(attributes = nil) ⇒ Base
Initializes a search with a search attributes Hash.
347 348 349 350 351 352 353 354 355 356 357 358 |
# File 'lib/search_api/search.rb', line 347 def initialize(attributes=nil) raise "Can't create an instance without model" if self.class.model.nil? # initialize attributes with ignored value self.attributes = self.class.search_attributes.inject((attributes || {}).dup) do |attributes, search_attribute| if attributes.has_key?(search_attribute) || attributes.has_key?(search_attribute.to_s) attributes else attributes.update(search_attribute => self.class.read_inheritable_attribute(:search_attribute_default_values)[search_attribute]) end end end |
Class Method Details
.model(*args) ⇒ Object
Without any argument, returns the model of this SearchApi::Search::Base class.
With a single argument, this method defines the model of this SearchApi::Search::Base class.
The model must respond_to the search_api_bridge
method, which should return an object that acts like SearchApi::Bridge::Base.
The model can’t be defined twice.
Some automatic search accessors may be defined when the model is set. See:
-
Bridge::Base#automatic_search_attribute_builders
-
Bridge::ActiveRecord#automatic_search_attribute_builders
Example:
class StuffSearch < SearchApi::Search::Base
# search for Stuff
model Stuff
...
end
StuffSearch.model # => Stuff
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 |
# File 'lib/search_api/search.rb', line 76 def model(*args) # returns model when no arguments return @model if args.empty? # can't set model twice raise "model is already set" if @model # fetch optional options = if args.last.is_a?(Hash) then args.pop else {} end # make sure model is the only last argument raise ArgumentError.new("Bad arguments for model") unless args.length == 1 model = args.first # assert model responds_to search_api_bridge raise ArgumentError.new("#{model} doesn't respond to search_api_bridge") unless model.respond_to?(:search_api_bridge) # set model @model = model # infer automatics search accessors from model add_automatic_search_attributes() nil # don't pollute class creation end |
.search_accessor(*args, &block) ⇒ Object
This is how you add search attributes to your SearchApi::Search::Base class.
Adding a search attribute has the following consequences:
-
A writer, a reader, an interrogation reader, and a ignored reader are defined.
Writer and reader act as usual. Interrogation reader acts as ActiveRecord::Base’s one.
Ignorer reader tells whether the search attribute is ignored or not.
# Defines following StuffSearch instance methods: # - :a, :a=, :a? and :a_ignored? # - :b, :b=, :b? and :b_ignored? class StuffSearch < SearchApi::Search::Base model Stuff search_accessor :a, :b end
-
The method
find_options_for_[search attribute]
is defined, if block is provided.
The optional block takes a single parameter: a SearchApi::Search::Base instance.
Its result should be enough to define a model search.
In case of ActiveRecord models, it should be a valid Hash that can be used as ActiveRecord::Base.find argument.
Example:
class StuffSearch < SearchApi::Search::Base
model Stuff
search_accessor :max_age do |search|
{ :conditions => ['birth_date > ?', Time.now - search.max_age.years]}
end
end
You can avoid passing a block, and define the find_options_for_[search attribute]
method later:
class StuffSearch < SearchApi::Search::Base
model Stuff
search_accessor :max_age
def
{ :conditions => ['birth_date > ?', Time.now - max_age.years]}
end
end
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 |
# File 'lib/search_api/search.rb', line 151 def search_accessor(*args, &block) # extract SearchAttributeBuilder instances from arguments search_attributes_builders = if block.nil? && args.length == 1 && args.first.is_a?(SearchAttributeBuilder) # argument is a single SearchAttributeBuilder instance args else # arguments are search attribute names and options = if args.last.is_a?(Hash) then args.pop else {} end args.map do |search_attribute| SearchAttributeBuilder.new(search_attribute, , &block) end end # define search attributes from builders search_attributes_builders.each do |builder| rewrite_search_attribute_builder(builder) add_search_attribute(builder) end nil # don't pollute class creation end |
.search_attributes ⇒ Object
189 190 191 |
# File 'lib/search_api/search.rb', line 189 def search_attributes read_inheritable_attribute(:search_attributes) || [] end |
Instance Method Details
#attributes ⇒ Object
Returns a Hash of search attributes.
363 364 365 366 367 |
# File 'lib/search_api/search.rb', line 363 def attributes self.class.search_attributes.inject({}) do |attributes, search_attribute| attributes.update(search_attribute => send(search_attribute)) end end |
#attributes=(attributes = nil) ⇒ Object
Sets search attributes via a Hash
370 371 372 373 374 |
# File 'lib/search_api/search.rb', line 370 def attributes=(attributes=nil) (attributes || {}).each do |search_attribute, value| send("#{search_attribute}=", value) end end |
#find_options ⇒ Object
Returns an object that should be enough to define a model search.
In case of ActiveRecord models, returns a valid Hash that can be used as ActiveRecord::Base.find argument.
393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 |
# File 'lib/search_api/search.rb', line 393 def # collect all find_options for not ignored attributes = self.class.search_attributes. # reject ignored attributes reject { |search_attribute| ignored?(search_attribute) }. # merge options for all attributes map { |search_attribute| send("find_options_for_#{search_attribute}") } # merge them options for not ignored attributes self.class.model.search_api_bridge.() end |