diff options
author | David Heinemeier Hansson <david@loudthinking.com> | 2006-05-21 17:32:37 +0000 |
---|---|---|
committer | David Heinemeier Hansson <david@loudthinking.com> | 2006-05-21 17:32:37 +0000 |
commit | 59c8c63ecd751136c5ed6d2e3c04a54af2025eb0 (patch) | |
tree | 050f58c08dff7884b70bb6a7d19fec925e98b632 /activerecord/lib | |
parent | fa207c24468b3b7c32b3c6d7128ec13a7b7d4a16 (diff) | |
download | rails-59c8c63ecd751136c5ed6d2e3c04a54af2025eb0.tar.gz rails-59c8c63ecd751136c5ed6d2e3c04a54af2025eb0.tar.bz2 rails-59c8c63ecd751136c5ed6d2e3c04a54af2025eb0.zip |
Added :allow_nil option for aggregations (closes #5091) [ian.w.white@gmail.com]
git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@4353 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
Diffstat (limited to 'activerecord/lib')
-rw-r--r-- | activerecord/lib/active_record/aggregations.rb | 59 |
1 files changed, 43 insertions, 16 deletions
diff --git a/activerecord/lib/active_record/aggregations.rb b/activerecord/lib/active_record/aggregations.rb index 3f524f591c..f6b604c118 100644 --- a/activerecord/lib/active_record/aggregations.rb +++ b/activerecord/lib/active_record/aggregations.rb @@ -118,46 +118,73 @@ module ActiveRecord # if the real class name is +CompanyAddress+, you'll have to specify it with this option. # * <tt>:mapping</tt> - specifies a number of mapping arrays (attribute, parameter) that bind an attribute name # to a constructor parameter on the value class. + # * <tt>:allow_nil</tt> - specifies that the aggregate object will not be instantiated when all mapped + # attributes are nil. Setting the aggregate class to nil has the effect of writing nil to all mapped attributes. + # This defaults to false. # # Option examples: # composed_of :temperature, :mapping => %w(reading celsius) # composed_of :balance, :class_name => "Money", :mapping => %w(balance amount) # composed_of :address, :mapping => [ %w(address_street street), %w(address_city city) ] # composed_of :gps_location + # composed_of :gps_location, :allow_nil => true + # def composed_of(part_id, options = {}) - options.assert_valid_keys(:class_name, :mapping) + options.assert_valid_keys(:class_name, :mapping, :allow_nil) name = part_id.id2name class_name = options[:class_name] || name.camelize - mapping = options[:mapping] || [ name, name ] + mapping = options[:mapping] || [ name, name ] + allow_nil = options[:allow_nil] || false - reader_method(name, class_name, mapping) - writer_method(name, class_name, mapping) + reader_method(name, class_name, mapping, allow_nil) + writer_method(name, class_name, mapping, allow_nil) create_reflection(:composed_of, part_id, options, self) end private - - def reader_method(name, class_name, mapping) + def reader_method(name, class_name, mapping, allow_nil) + mapping = (Array === mapping.first ? mapping : [ mapping ]) + + allow_nil_condition = if allow_nil + mapping.collect { |pair| "!read_attribute(\"#{pair.first}\").nil?"}.join(" && ") + else + "true" + end + module_eval <<-end_eval def #{name}(force_reload = false) - if @#{name}.nil? || force_reload - @#{name} = #{class_name}.new(#{(Array === mapping.first ? mapping : [ mapping ]).collect{ |pair| "read_attribute(\"#{pair.first}\")"}.join(", ")}) + if (@#{name}.nil? || force_reload) && #{allow_nil_condition} + @#{name} = #{class_name}.new(#{mapping.collect { |pair| "read_attribute(\"#{pair.first}\")"}.join(", ")}) end - return @#{name} end end_eval end - def writer_method(name, class_name, mapping) - module_eval <<-end_eval - def #{name}=(part) - @#{name} = part.freeze - #{(Array === mapping.first ? mapping : [ mapping ]).collect{ |pair| "@attributes[\"#{pair.first}\"] = part.#{pair.last}" }.join("\n")} - end - end_eval + def writer_method(name, class_name, mapping, allow_nil) + mapping = (Array === mapping.first ? mapping : [ mapping ]) + + if allow_nil + module_eval <<-end_eval + def #{name}=(part) + if part.nil? + #{mapping.collect { |pair| "@attributes[\"#{pair.first}\"] = nil" }.join("\n")} + else + @#{name} = part.freeze + #{mapping.collect { |pair| "@attributes[\"#{pair.first}\"] = part.#{pair.last}" }.join("\n")} + end + end + end_eval + else + module_eval <<-end_eval + def #{name}=(part) + @#{name} = part.freeze + #{mapping.collect{ |pair| "@attributes[\"#{pair.first}\"] = part.#{pair.last}" }.join("\n")} + end + end_eval + end end end end |