# File lib/active_record/dynamic_matchers.rb, line 3 3: def respond_to?(method_id, include_private = false) 4: if match = DynamicFinderMatch.match(method_id) 5: return true if all_attributes_exists?(match.attribute_names) 6: elsif match = DynamicScopeMatch.match(method_id) 7: return true if all_attributes_exists?(match.attribute_names) 8: end 9: 10: super 11: end
# File lib/active_record/dynamic_matchers.rb, line 77 77: def aggregate_mapping(reflection) 78: mapping = reflection.options[:mapping] || [reflection.name, reflection.name] 79: mapping.first.is_a?(Array) ? mapping : [mapping] 80: end
# File lib/active_record/dynamic_matchers.rb, line 72 72: def all_attributes_exists?(attribute_names) 73: (expand_attribute_names_for_aggregates(attribute_names) - 74: column_methods_hash.keys).empty? 75: end
Similar in purpose to expand_hash_conditions_for_aggregates.
# File lib/active_record/dynamic_matchers.rb, line 60 60: def expand_attribute_names_for_aggregates(attribute_names) 61: attribute_names.map { |attribute_name| 62: unless (aggregation = reflect_on_aggregation(attribute_name.to_sym)).nil? 63: aggregate_mapping(aggregation).map do |field_attr, _| 64: field_attr.to_sym 65: end 66: else 67: attribute_name.to_sym 68: end 69: }.flatten 70: end
Enables dynamic finders like User.find_by_user_name(user_name) and User.scoped_by_user_name(user_name). Refer to Dynamic attribute-based finders section at the top of this file for more detailed information.
It’s even possible to use all the additional parameters to find. For example, the full interface for find_all_by_amount is actually find_all_by_amount(amount, options).
Each dynamic finder using scoped_by_* is also defined in the class after it is first invoked, so that future attempts to use it do not run through method_missing.
# File lib/active_record/dynamic_matchers.rb, line 24 24: def method_missing(method_id, *arguments, &block) 25: if match = (DynamicFinderMatch.match(method_id) || DynamicScopeMatch.match(method_id)) 26: attribute_names = match.attribute_names 27: super unless all_attributes_exists?(attribute_names) 28: if !(match.is_a?(DynamicFinderMatch) && match.instantiator? && arguments.first.is_a?(Hash)) && arguments.size < attribute_names.size 29: method_trace = "#{__FILE__}:#{__LINE__}:in `#{method_id}'" 30: backtrace = [method_trace] + caller 31: raise ArgumentError, "wrong number of arguments (#{arguments.size} for #{attribute_names.size})", backtrace 32: end 33: if match.respond_to?(:scope?) && match.scope? 34: self.class_eval def self.#{method_id}(*args) # def self.scoped_by_user_name_and_password(*args) attributes = Hash[[:#{attribute_names.join(',:')}].zip(args)] # attributes = Hash[[:user_name, :password].zip(args)] # scoped(:conditions => attributes) # scoped(:conditions => attributes) end # end, __FILE__, __LINE__ + 1 35: send(method_id, *arguments) 36: elsif match.finder? 37: options = if arguments.length > attribute_names.size 38: arguments.extract_options! 39: else 40: {} 41: end 42: 43: relation = options.any? ? scoped(options) : scoped 44: relation.send :find_by_attributes, match, attribute_names, *arguments, &block 45: elsif match.instantiator? 46: scoped.send :find_or_instantiator_by_attributes, match, attribute_names, *arguments, &block 47: end 48: else 49: super 50: end 51: end
Disabled; run with --debug to generate this.
Generated with the Darkfish Rdoc Generator 1.1.6.