Class: MetaSearch::Method
- Inherits:
-
Object
- Object
- MetaSearch::Method
- Includes:
- Utility
- Defined in:
- lib/meta_search/method.rb
Overview
MetaSearch can be given access to any class method on your model to extend its search capabilities. The only rule is that the method must return an ActiveRecord::Relation so that MetaSearch can continue to extend the search with other attributes. Conveniently, scopes (formerly “named scopes”) do this already.
Consider the following model:
class Company < ActiveRecord::Base
has_many :slackers, :class_name => "Developer", :conditions => {:slacker => true}
scope :backwards_name, lambda {|name| where(:name => name.reverse)}
scope :with_slackers_by_name_and_salary_range,
lambda {|name, low, high|
joins(:slackers).where(:developers => {:name => name, :salary => low..high})
}
end
To allow MetaSearch access to a model method, including a named scope, just use search_methods in the model:
search_methods :backwards_name
This will allow you to add a text field named :backwards_name to your search form, and it will behave as you might expect.
In the case of the second scope, we have multiple parameters to pass in, of different types. We can pass the following to search_methods:
search_methods :with_slackers_by_name_and_salary_range,
:splat_param => true, :type => [:string, :integer, :integer]
MetaSearch needs us to tell it that we don’t want to keep the array supplied to it as-is, but “splat” it when passing it to the model method. And in this case, ActiveRecord would have been smart enough to handle the typecasting for us, but I wanted to demonstrate how we can tell MetaSearch that a given parameter is of a specific database “column type.” This is just a hint MetaSearch uses in the same way it does when casting “Where” params based on the DB column being searched. It’s also important so that things like dates get handled properly by FormBuilder.
NOTE: If you do supply an array, rather than a single type value, to :type, MetaSearch will enforce that any array supplied for input by your forms has the correct number of elements for your eventual method.
Besides :splat_param and :type, search_methods accept the same :formatter and :validator options that you would use when adding a new MetaSearch::Where:
formatter is the Proc that will do any formatting to the variable passed to your method. The default proc is {|param| param}, which doesn’t really do anything. If you pass a string, it will be evaled in the context of this Proc.
If your method will do a LIKE search against its parameter, you might want to pass:
:formatter => '"%#{param}%"'
Be sure to single-quote the string, so that variables aren’t interpolated until later. If in doubt, just use a Proc, like so:
:formatter => Proc.new {|param| "%#{param}%"}
validator is the Proc that will be used to check whether a parameter supplied to the method is valid. If it is not valid, it won’t be used in the query. The default is {|param| !param.blank?}, so that empty parameters aren’t added to the search, but you can get more complex if you desire. Validations are run after typecasting, so you can check the class of your parameters, for instance.
Constant Summary
Constants included from Utility
Utility::FALSE_VALUES, Utility::TRUE_VALUES
Instance Attribute Summary collapse
-
#formatter ⇒ Object
readonly
Returns the value of attribute formatter.
-
#name ⇒ Object
readonly
Returns the value of attribute name.
-
#type ⇒ Object
readonly
Returns the value of attribute type.
-
#validator ⇒ Object
readonly
Returns the value of attribute validator.
Instance Method Summary collapse
-
#cast_param(param) ⇒ Object
Cast the parameter to the type specified in the Method’s
type. -
#evaluate(relation, param) ⇒ Object
Evaluate the method in the context of the supplied relation and parameter.
-
#format_param(param) ⇒ Object
Format a parameter for searching using the Method’s defined formatter.
-
#initialize(name, opts = {}) ⇒ Method
constructor
A new instance of Method.
- #splat_param? ⇒ Boolean
-
#validate(param) ⇒ Object
Validate the parameter for use in a search using the Method’s defined validator.
Constructor Details
#initialize(name, opts = {}) ⇒ Method
Returns a new instance of Method.
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
# File 'lib/meta_search/method.rb', line 71 def initialize(name, opts ={}) raise ArgumentError, "Name parameter required" if name.blank? @name = name @type = opts[:type] || :string @splat_param = opts[:splat_param] || false @formatter = opts[:formatter] || Proc.new {|param| param} if @formatter.is_a?(String) formatter = @formatter @formatter = Proc.new {|param| eval formatter} end unless @formatter.respond_to?(:call) raise ArgumentError, "Invalid formatter for #{name}, should be a Proc or String." end @validator = opts[:validator] || Proc.new {|param| !param.blank?} unless @validator.respond_to?(:call) raise ArgumentError, "Invalid validator for #{name}, should be a Proc." end end |
Instance Attribute Details
#formatter ⇒ Object (readonly)
Returns the value of attribute formatter.
69 70 71 |
# File 'lib/meta_search/method.rb', line 69 def formatter @formatter end |
#name ⇒ Object (readonly)
Returns the value of attribute name.
69 70 71 |
# File 'lib/meta_search/method.rb', line 69 def name @name end |
#type ⇒ Object (readonly)
Returns the value of attribute type.
69 70 71 |
# File 'lib/meta_search/method.rb', line 69 def type @type end |
#validator ⇒ Object (readonly)
Returns the value of attribute validator.
69 70 71 |
# File 'lib/meta_search/method.rb', line 69 def validator @validator end |
Instance Method Details
#cast_param(param) ⇒ Object
Cast the parameter to the type specified in the Method’s type
91 92 93 94 95 96 97 98 99 100 101 102 103 104 |
# File 'lib/meta_search/method.rb', line 91 def cast_param(param) if type.is_a?(Array) unless param.is_a?(Array) && param.size == type.size num_params = param.is_a?(Array) ? param.size : 1 raise ArgumentError, "Parameters supplied to #{name} could not be type cast -- #{num_params} values supplied, #{type.size} expected" end type.each_with_index do |t, i| param[i] = cast_attributes(t, param[i]) end param else cast_attributes(type, param) end end |
#evaluate(relation, param) ⇒ Object
Evaluate the method in the context of the supplied relation and parameter
107 108 109 110 111 112 113 |
# File 'lib/meta_search/method.rb', line 107 def evaluate(relation, param) if splat_param? relation.send(name, *format_param(param)) else relation.send(name, format_param(param)) end end |
#format_param(param) ⇒ Object
Format a parameter for searching using the Method’s defined formatter.
120 121 122 |
# File 'lib/meta_search/method.rb', line 120 def format_param(param) formatter.call(param) end |
#splat_param? ⇒ Boolean
115 116 117 |
# File 'lib/meta_search/method.rb', line 115 def splat_param? !!@splat_param end |
#validate(param) ⇒ Object
Validate the parameter for use in a search using the Method’s defined validator.
125 126 127 |
# File 'lib/meta_search/method.rb', line 125 def validate(param) validator.call(param) end |