有人会善意地解剖合并!方法?它对条件和变量赋值的使用看起来相当简洁,而且我很难跟上它。很想听到一位精通Ruby的开发人员打破这种局面。
module ActiveRecord
class Errors
def merge!(errors, options={})
fields_to_merge = if only=options[:only]
only
elsif except=options[:except]
except = [except] unless except.is_a?(Array)
except.map!(&:to_sym)
errors.entries.map(&:first).select do |field|
!except.include?(field.to_sym)
end
else
errors.entries.map(&:first)
end
fields_to_merge = [fields_to_merge] unless fields_to_merge.is_a?(Array)
fields_to_merge.map!(&:to_sym)
errors.entries.each do |field, msg|
add field, msg if fields_to_merge.include?(field.to_sym)
end
end
end
end
答案 0 :(得分:7)
module ActiveRecord
class Errors
def merge!(errors, options={})
# This method has two major sections.
# 1. Figure out which fields we want to merge, based on the options.
# First check to see if we're supposed to whitelist or blacklist
# any fields.
# fields_to_merge is simple being assigned the return value of
# the if/elsif/else block.
#
fields_to_merge = if only=options[:only]
# Whitelist
# Implies that options[:only] looks like :only => :foo, but that
# seems short-sighted and should probably be refactored to work
# like the blacklist, complete with to_sym conversions.
only
elsif except=options[:except]
# Blacklist
# You can pass in a single field or an array.
# :except => [:foo, :bar, :yourmom] or :except => :foo
# In the latter case, this is about to be converted to [:foo] so that
# it's an array either way.
except = [except] unless except.is_a?(Array)
# For each array element, convert that element to a symbol.
# "foo" becomes :foo
# This is a short hand for "map" which is equivalent to the following:
# except.map!{|field| field.to_sym}
except.map!(&:to_sym)
# The "entries" method comes from Enumerable and works like to_a.
# In the case of a hash, you end up with an array of arrays.
# Assuming there are already errors, the output of that will look
# something like:
# [['user', 'can't be blank'], ['some_other_field', 'has problems']]
#
# Mapping this to :first means "send the 'first' message to each array
# element. Since the elements are themselves arrays, you end up
# with ['user', 'some_other_field']
#
# Now we do a 'select' on that array, looking for any field names that
# aren't in our 'except' array.
errors.entries.map(&:first).select do |field|
!except.include?(field.to_sym)
end
else
# No filters. Just dump out an array of all field names.
errors.entries.map(&:first)
end
# Make sure that we have an array, which at this point is only possible
# if we're using an :only => :foo.
fields_to_merge = [fields_to_merge] unless fields_to_merge.is_a?(Array)
# Make sure that they are all symbols (again with the :only, see the
# note above about refactoring).
fields_to_merge.map!(&:to_sym)
# 2. Now we know what fields we care about, yank in any errors with a
# matching field name from the errors object.
errors.entries.each do |field, msg|
# 'add' is a method on ActiveRecord::Errors that adds a new error
# message for the given attribute (field).
# In this case, any error from the errors object passed into this
# method with a field name that appears in the 'fields_to_merge'
# array is added to the existing errors object.
#
add field, msg if fields_to_merge.include?(field.to_sym)
end
end
end
end