Class: MetaSearch::Builder
- Inherits:
-
Object
- Object
- MetaSearch::Builder
- Includes:
- ModelCompatibility, Utility
- Defined in:
- lib/meta_search/builder.rb
Overview
Builder is the workhorse of MetaSearch – it is the class that handles dynamically generating methods based on a supplied model, and is what gets instantiated when you call your model’s search method. Builder doesn’t generate any methods until they’re needed, using method_missing to compare requested method names against your model’s attributes, associations, and the configured Where list.
Attributes
-
base- The base model that Builder wraps. -
search_attributes- Attributes that have been assigned (search terms) -
relation- The ActiveRecord::Relation representing the current search. -
join_dependency- The JoinDependency object representing current association join dependencies. It’s used internally to avoid joining association tables more than once when constructing search queries.
Constant Summary
Constants included from Utility
Utility::FALSE_VALUES, Utility::TRUE_VALUES
Instance Attribute Summary collapse
-
#base ⇒ Object
readonly
Returns the value of attribute base.
-
#errors ⇒ Object
readonly
Returns the value of attribute errors.
-
#join_dependency ⇒ Object
readonly
Returns the value of attribute join_dependency.
-
#options ⇒ Object
readonly
Returns the value of attribute options.
-
#relation ⇒ Object
readonly
Returns the value of attribute relation.
-
#search_attributes ⇒ Object
readonly
Returns the value of attribute search_attributes.
-
#search_key ⇒ Object
readonly
Returns the value of attribute search_key.
Instance Method Summary collapse
-
#build(option_hash) ⇒ Object
Build the search with the given search options.
- #get_association(assoc, base = @base) ⇒ Object
- #get_attribute(name, parent = @join_dependency.join_base) ⇒ Object
- #get_column(column, base = @base) ⇒ Object
-
#initialize(base_or_relation, opts = {}) ⇒ Builder
constructor
Initialize a new Builder.
- #respond_to?(method_id, include_private = false) ⇒ Boolean
Methods included from ModelCompatibility
included, #persisted?, #to_key, #to_model, #to_param
Constructor Details
#initialize(base_or_relation, opts = {}) ⇒ Builder
Initialize a new Builder. Requires a base model to wrap, and supports a couple of options for how it will expose this model and its associations to your controllers/views.
31 32 33 34 35 36 37 38 39 40 41 42 |
# File 'lib/meta_search/builder.rb', line 31 def initialize(base_or_relation, opts = {}) opts = opts.dup @relation = base_or_relation.scoped @base = @relation.klass @search_key = (opts.delete(:search_key) || 'search').to_s @options = opts # Let's just hang on to other options for use in authorization blocks @join_type = opts[:join_type] || Arel::Nodes::OuterJoin @join_type = get_join_type(@join_type) @join_dependency = build_join_dependency(@relation) @search_attributes = {} @errors = ActiveModel::Errors.new(self) end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(method_id, *args, &block) ⇒ Object (private)
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 |
# File 'lib/meta_search/builder.rb', line 122 def method_missing(method_id, *args, &block) method_name = method_id.to_s if method_name =~ /^meta_sort=?$/ (args.any? || method_name =~ /=$/) ? set_sort(args.first) : get_sort elsif match = method_name.match(/^(.*)\(([0-9]+).*\)$/) # Multiparameter reader method_name, index = match.captures vals = self.send(method_name) vals.is_a?(Array) ? vals[index.to_i - 1] : nil elsif match = matches_named_method(method_name) (args.any? || method_name =~ /=$/) ? set_named_method_value(match, args.first) : get_named_method_value(match) elsif match = matches_attribute_method(method_id) attribute, predicate = match.captures (args.any? || method_name =~ /=$/) ? set_attribute_method_value(attribute, predicate, args.first) : get_attribute_method_value(attribute, predicate) else super end end |
Instance Attribute Details
#base ⇒ Object (readonly)
Returns the value of attribute base.
26 27 28 |
# File 'lib/meta_search/builder.rb', line 26 def base @base end |
#errors ⇒ Object (readonly)
Returns the value of attribute errors.
26 27 28 |
# File 'lib/meta_search/builder.rb', line 26 def errors @errors end |
#join_dependency ⇒ Object (readonly)
Returns the value of attribute join_dependency.
26 27 28 |
# File 'lib/meta_search/builder.rb', line 26 def join_dependency @join_dependency end |
#options ⇒ Object (readonly)
Returns the value of attribute options.
26 27 28 |
# File 'lib/meta_search/builder.rb', line 26 def @options end |
#relation ⇒ Object (readonly)
Returns the value of attribute relation.
26 27 28 |
# File 'lib/meta_search/builder.rb', line 26 def relation @relation end |
#search_attributes ⇒ Object (readonly)
Returns the value of attribute search_attributes.
26 27 28 |
# File 'lib/meta_search/builder.rb', line 26 def search_attributes @search_attributes end |
#search_key ⇒ Object (readonly)
Returns the value of attribute search_key.
26 27 28 |
# File 'lib/meta_search/builder.rb', line 26 def search_key @search_key end |
Instance Method Details
#build(option_hash) ⇒ Object
Build the search with the given search options. Options are in the form of a hash with keys matching the names creted by the Builder’s “wheres” as outlined in MetaSearch::Where
83 84 85 86 87 88 89 90 |
# File 'lib/meta_search/builder.rb', line 83 def build(option_hash) opts = option_hash.dup || {} @relation = @base.scoped opts.stringify_keys! opts = (opts) assign_attributes(opts) self end |
#get_association(assoc, base = @base) ⇒ Object
48 49 50 |
# File 'lib/meta_search/builder.rb', line 48 def get_association(assoc, base = @base) base.reflect_on_association(assoc.to_sym) if base.(assoc, self) end |
#get_attribute(name, parent = @join_dependency.join_base) ⇒ Object
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
# File 'lib/meta_search/builder.rb', line 52 def get_attribute(name, parent = @join_dependency.join_base) attribute = nil if get_column(name, parent.active_record) attribute = parent.table[name] elsif (segments = name.to_s.split(/_/)).size > 1 remainder = [] found_assoc = nil while remainder.unshift(segments.pop) && segments.size > 0 && !found_assoc do if found_assoc = get_association(segments.join('_'), parent.active_record) if found_assoc.[:polymorphic] unless delimiter = remainder.index('type') raise PolymorphicAssociationMissingTypeError, "Polymorphic association specified without a type" end polymorphic_class, attribute_name = remainder[0...delimiter].join('_'), remainder[delimiter + 1...remainder.size].join('_') polymorphic_class = polymorphic_class.classify.constantize join = build_or_find_association(found_assoc.name, parent, polymorphic_class) attribute = get_attribute(attribute_name, join) else join = build_or_find_association(found_assoc.name, parent, found_assoc.klass) attribute = get_attribute(remainder.join('_'), join) end end end end attribute end |
#get_column(column, base = @base) ⇒ Object
44 45 46 |
# File 'lib/meta_search/builder.rb', line 44 def get_column(column, base = @base) base.columns_hash[column.to_s] if base.(column, self) end |
#respond_to?(method_id, include_private = false) ⇒ Boolean
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 |
# File 'lib/meta_search/builder.rb', line 92 def respond_to?(method_id, include_private = false) return true if super method_name = method_id.to_s if RELATION_METHODS.map(&:to_s).include?(method_name) true elsif method_name.match(/^meta_sort=?$/) true elsif match = method_name.match(/^(.*)\(([0-9]+).*\)$/) method_name, index = match.captures respond_to?(method_name) elsif matches_named_method(method_name) || matches_attribute_method(method_name) true else false end end |