diff options
author | Rafael Mendonça França <rafaelmfranca@gmail.com> | 2014-06-26 06:40:08 -0300 |
---|---|---|
committer | Rafael Mendonça França <rafaelmfranca@gmail.com> | 2014-06-26 06:40:08 -0300 |
commit | 2571c3f415ac0c6eacedbc199e31b1c77e7bacc4 (patch) | |
tree | e1f9c5ed4433076cec7d2b9e0341f48dcca6fdab /activerecord/lib | |
parent | 781370998d59bd45b951e0724ccf98871ecb68d2 (diff) | |
parent | a89f8a922d8f37245f3ca60748adc5f4c8ee88d2 (diff) | |
download | rails-2571c3f415ac0c6eacedbc199e31b1c77e7bacc4.tar.gz rails-2571c3f415ac0c6eacedbc199e31b1c77e7bacc4.tar.bz2 rails-2571c3f415ac0c6eacedbc199e31b1c77e7bacc4.zip |
Merge pull request #15868 from sgrif/sg-uninitialized-attributes
Move behavior of `read_attribute` to `AttributeSet`
Conflicts:
activerecord/lib/active_record/attribute_set.rb
activerecord/test/cases/attribute_set_test.rb
Diffstat (limited to 'activerecord/lib')
-rw-r--r-- | activerecord/lib/active_record.rb | 2 | ||||
-rw-r--r-- | activerecord/lib/active_record/attribute.rb | 27 | ||||
-rw-r--r-- | activerecord/lib/active_record/attribute_methods/read.rb | 13 | ||||
-rw-r--r-- | activerecord/lib/active_record/attribute_set.rb | 41 | ||||
-rw-r--r-- | activerecord/lib/active_record/attribute_set/builder.rb | 33 |
5 files changed, 88 insertions, 28 deletions
diff --git a/activerecord/lib/active_record.rb b/activerecord/lib/active_record.rb index ab85414277..17b00bbaea 100644 --- a/activerecord/lib/active_record.rb +++ b/activerecord/lib/active_record.rb @@ -27,12 +27,12 @@ require 'active_model' require 'arel' require 'active_record/version' +require 'active_record/attribute_set' module ActiveRecord extend ActiveSupport::Autoload autoload :Attribute - autoload :AttributeSet autoload :Base autoload :Callbacks autoload :Core diff --git a/activerecord/lib/active_record/attribute.rb b/activerecord/lib/active_record/attribute.rb index da8eb10dc6..6c0b81b3fe 100644 --- a/activerecord/lib/active_record/attribute.rb +++ b/activerecord/lib/active_record/attribute.rb @@ -8,6 +8,10 @@ module ActiveRecord def from_user(value, type) FromUser.new(value, type) end + + def uninitialized(type) + Uninitialized.new(type) + end end attr_reader :value_before_type_cast, :type @@ -41,6 +45,10 @@ module ActiveRecord raise NotImplementedError end + def initialized? + true + end + protected def initialize_dup(other) @@ -69,6 +77,25 @@ module ActiveRecord false end alias changed_in_place_from? changed_from? + + def initialized? + true + end + end + end + + class Uninitialized < Attribute # :nodoc: + def initialize(type) + super(nil, type) + end + + def value + nil + end + alias value_for_database value + + def initialized? + false end end end diff --git a/activerecord/lib/active_record/attribute_methods/read.rb b/activerecord/lib/active_record/attribute_methods/read.rb index 8c1cc128f7..10869dfc1e 100644 --- a/activerecord/lib/active_record/attribute_methods/read.rb +++ b/activerecord/lib/active_record/attribute_methods/read.rb @@ -81,17 +81,10 @@ module ActiveRecord # Returns the value of the attribute identified by <tt>attr_name</tt> after # it has been typecast (for example, "2004-12-12" in a date column is cast # to a date object, like Date.new(2004, 12, 12)). - def read_attribute(attr_name) + def read_attribute(attr_name, &block) name = attr_name.to_s - @attributes.fetch(name) { - if name == 'id' - return read_attribute(self.class.primary_key) - elsif block_given? && self.class.columns_hash.key?(name) - return yield(name) - else - return nil - end - }.value + name = self.class.primary_key if name == 'id' + @attributes.fetch_value(name, &block) end private diff --git a/activerecord/lib/active_record/attribute_set.rb b/activerecord/lib/active_record/attribute_set.rb index 99fc9b6ac6..68382756a4 100644 --- a/activerecord/lib/active_record/attribute_set.rb +++ b/activerecord/lib/active_record/attribute_set.rb @@ -1,6 +1,9 @@ +require 'active_record/attribute_set/builder' + module ActiveRecord class AttributeSet # :nodoc: - delegate :[], :[]=, :fetch, :include?, :keys, to: :attributes + delegate :[], :[]=, to: :attributes + delegate :keys, to: :initialized_attributes def initialize(attributes) @attributes = attributes @@ -11,10 +14,23 @@ module ActiveRecord end def to_hash - attributes.each_with_object({}) { |(k, v), h| h[k] = v.value } + initialized_attributes.each_with_object({}) { |(k, v), h| h[k] = v.value } end alias_method :to_h, :to_hash + def include?(name) + attributes.include?(name) && self[name].initialized? + end + + def fetch_value(name) + attribute = self[name] + if attribute.initialized? || !block_given? + attribute.value + else + yield name + end + end + def freeze @attributes.freeze super @@ -34,23 +50,14 @@ module ActiveRecord super end - class Builder # :nodoc: - def initialize(types) - @types = types - end - - def build_from_database(values, additional_types = {}) - attributes = Hash.new(Attribute::Null) - values.each_with_object(attributes) do |(name, value), hash| - type = additional_types.fetch(name, @types[name]) - hash[name] = Attribute.from_database(value, type) - end - AttributeSet.new(attributes) - end - end - protected attr_reader :attributes + + private + + def initialized_attributes + attributes.select { |_, attr| attr.initialized? } + end end end diff --git a/activerecord/lib/active_record/attribute_set/builder.rb b/activerecord/lib/active_record/attribute_set/builder.rb new file mode 100644 index 0000000000..d91720d5e1 --- /dev/null +++ b/activerecord/lib/active_record/attribute_set/builder.rb @@ -0,0 +1,33 @@ +module ActiveRecord + class AttributeSet # :nodoc: + class Builder # :nodoc: + attr_reader :types + + def initialize(types) + @types = types + end + + def build_from_database(values, additional_types = {}) + attributes = build_attributes_from_values(values, additional_types) + add_uninitialized_attributes(attributes) + AttributeSet.new(attributes) + end + + private + + def build_attributes_from_values(values, additional_types) + attributes = Hash.new(Attribute::Null) + values.each_with_object(attributes) do |(name, value), hash| + type = additional_types.fetch(name, types[name]) + hash[name] = Attribute.from_database(value, type) + end + end + + def add_uninitialized_attributes(attributes) + types.except(*attributes.keys).each do |name, type| + attributes[name] = Attribute.uninitialized(type) + end + end + end + end +end |