aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSean Griffin <sean@thoughtbot.com>2015-02-10 08:20:54 -0700
committerSean Griffin <sean@thoughtbot.com>2015-02-10 08:21:46 -0700
commit2f8c596d1beb46acd8a74f0e6d5c1c48a29dcee9 (patch)
tree0915ec2f0975e4bb98b26e43475562dbed34261c
parentd89912b9bef03f76f355e807476edd292cc293bc (diff)
downloadrails-2f8c596d1beb46acd8a74f0e6d5c1c48a29dcee9.tar.gz
rails-2f8c596d1beb46acd8a74f0e6d5c1c48a29dcee9.tar.bz2
rails-2f8c596d1beb46acd8a74f0e6d5c1c48a29dcee9.zip
Maintain a consistent order in `ActiveRecord::Base#attributes`
Fixes #18871
-rw-r--r--activerecord/lib/active_record/attribute_set/builder.rb12
-rw-r--r--activerecord/test/cases/attribute_set_test.rb10
2 files changed, 21 insertions, 1 deletions
diff --git a/activerecord/lib/active_record/attribute_set/builder.rb b/activerecord/lib/active_record/attribute_set/builder.rb
index 0f3c285a80..e85777c335 100644
--- a/activerecord/lib/active_record/attribute_set/builder.rb
+++ b/activerecord/lib/active_record/attribute_set/builder.rb
@@ -20,7 +20,7 @@ module ActiveRecord
end
class LazyAttributeHash # :nodoc:
- delegate :select, :transform_values, :each_key, to: :materialize
+ delegate :transform_values, :each_key, to: :materialize
def initialize(types, values, additional_types)
@types = types
@@ -50,6 +50,16 @@ module ActiveRecord
super
end
+ def select
+ keys = types.keys | values.keys | delegate_hash.keys
+ keys.each_with_object({}) do |key, hash|
+ attribute = self[key]
+ if yield(key, attribute)
+ hash[key] = attribute
+ end
+ end
+ end
+
protected
attr_reader :types, :values, :additional_types, :delegate_hash
diff --git a/activerecord/test/cases/attribute_set_test.rb b/activerecord/test/cases/attribute_set_test.rb
index 8025c7c4d2..112cd2fb14 100644
--- a/activerecord/test/cases/attribute_set_test.rb
+++ b/activerecord/test/cases/attribute_set_test.rb
@@ -65,6 +65,16 @@ module ActiveRecord
assert_equal({ foo: 1, bar: 2.2 }, attributes.to_h)
end
+ test "to_hash maintains order" do
+ builder = AttributeSet::Builder.new(foo: Type::Integer.new, bar: Type::Float.new)
+ attributes = builder.build_from_database(foo: '2.2', bar: '3.3')
+
+ attributes[:bar]
+ hash = attributes.to_h
+
+ assert_equal [[:foo, 2], [:bar, 3.3]], hash.to_a
+ end
+
test "values_before_type_cast" do
builder = AttributeSet::Builder.new(foo: Type::Integer.new, bar: Type::Integer.new)
attributes = builder.build_from_database(foo: '1.1', bar: '2.2')