activerecord 4.1.16 → 4.2.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +634 -2185
- data/README.rdoc +15 -10
- data/lib/active_record.rb +2 -1
- data/lib/active_record/aggregations.rb +12 -8
- data/lib/active_record/associations.rb +58 -33
- data/lib/active_record/associations/association.rb +1 -1
- data/lib/active_record/associations/association_scope.rb +53 -21
- data/lib/active_record/associations/belongs_to_association.rb +15 -5
- data/lib/active_record/associations/builder/association.rb +16 -5
- data/lib/active_record/associations/builder/belongs_to.rb +7 -29
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +2 -11
- data/lib/active_record/associations/builder/has_one.rb +2 -2
- data/lib/active_record/associations/builder/singular_association.rb +8 -1
- data/lib/active_record/associations/collection_association.rb +32 -44
- data/lib/active_record/associations/collection_proxy.rb +1 -10
- data/lib/active_record/associations/has_many_association.rb +60 -14
- data/lib/active_record/associations/has_many_through_association.rb +34 -23
- data/lib/active_record/associations/has_one_association.rb +0 -1
- data/lib/active_record/associations/join_dependency.rb +7 -9
- data/lib/active_record/associations/join_dependency/join_association.rb +18 -14
- data/lib/active_record/associations/preloader.rb +2 -2
- data/lib/active_record/associations/preloader/association.rb +9 -5
- data/lib/active_record/associations/preloader/through_association.rb +3 -3
- data/lib/active_record/associations/singular_association.rb +16 -1
- data/lib/active_record/associations/through_association.rb +6 -22
- data/lib/active_record/attribute.rb +131 -0
- data/lib/active_record/attribute_assignment.rb +19 -11
- data/lib/active_record/attribute_decorators.rb +66 -0
- data/lib/active_record/attribute_methods.rb +53 -90
- data/lib/active_record/attribute_methods/before_type_cast.rb +2 -2
- data/lib/active_record/attribute_methods/dirty.rb +85 -42
- data/lib/active_record/attribute_methods/primary_key.rb +6 -8
- data/lib/active_record/attribute_methods/read.rb +14 -57
- data/lib/active_record/attribute_methods/serialization.rb +12 -146
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +32 -40
- data/lib/active_record/attribute_methods/write.rb +8 -23
- data/lib/active_record/attribute_set.rb +77 -0
- data/lib/active_record/attribute_set/builder.rb +32 -0
- data/lib/active_record/attributes.rb +122 -0
- data/lib/active_record/autosave_association.rb +11 -21
- data/lib/active_record/base.rb +9 -19
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +69 -45
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +22 -42
- data/lib/active_record/connection_adapters/abstract/quoting.rb +59 -60
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +37 -2
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +102 -21
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +9 -33
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +178 -55
- data/lib/active_record/connection_adapters/abstract/transaction.rb +120 -115
- data/lib/active_record/connection_adapters/abstract_adapter.rb +143 -57
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +156 -107
- data/lib/active_record/connection_adapters/column.rb +13 -244
- data/lib/active_record/connection_adapters/connection_specification.rb +6 -20
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +12 -15
- data/lib/active_record/connection_adapters/mysql_adapter.rb +55 -143
- data/lib/active_record/connection_adapters/postgresql/array_parser.rb +15 -27
- data/lib/active_record/connection_adapters/postgresql/column.rb +20 -0
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +39 -20
- data/lib/active_record/connection_adapters/postgresql/oid.rb +29 -388
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +96 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +52 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +14 -0
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +46 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +11 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +27 -0
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +17 -0
- data/lib/active_record/connection_adapters/postgresql/oid/float.rb +21 -0
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +59 -0
- data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +11 -0
- data/lib/active_record/connection_adapters/postgresql/oid/json.rb +35 -0
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +23 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +43 -0
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +43 -0
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +76 -0
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/time.rb +11 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +85 -0
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +26 -0
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +26 -0
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +28 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +42 -122
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +4 -4
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +154 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +86 -34
- data/lib/active_record/connection_adapters/postgresql/utils.rb +66 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +188 -452
- data/lib/active_record/connection_adapters/schema_cache.rb +14 -28
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +54 -47
- data/lib/active_record/connection_handling.rb +1 -1
- data/lib/active_record/core.rb +119 -22
- data/lib/active_record/counter_cache.rb +60 -6
- data/lib/active_record/enum.rb +9 -10
- data/lib/active_record/errors.rb +27 -26
- data/lib/active_record/explain.rb +1 -1
- data/lib/active_record/fixtures.rb +52 -45
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +33 -8
- data/lib/active_record/integration.rb +4 -4
- data/lib/active_record/locking/optimistic.rb +34 -16
- data/lib/active_record/migration.rb +22 -32
- data/lib/active_record/migration/command_recorder.rb +19 -2
- data/lib/active_record/migration/join_table.rb +1 -1
- data/lib/active_record/model_schema.rb +39 -48
- data/lib/active_record/nested_attributes.rb +8 -18
- data/lib/active_record/persistence.rb +39 -22
- data/lib/active_record/query_cache.rb +3 -3
- data/lib/active_record/querying.rb +1 -8
- data/lib/active_record/railtie.rb +17 -10
- data/lib/active_record/railties/databases.rake +47 -42
- data/lib/active_record/readonly_attributes.rb +0 -1
- data/lib/active_record/reflection.rb +225 -92
- data/lib/active_record/relation.rb +35 -11
- data/lib/active_record/relation/batches.rb +0 -2
- data/lib/active_record/relation/calculations.rb +28 -32
- data/lib/active_record/relation/delegation.rb +1 -1
- data/lib/active_record/relation/finder_methods.rb +42 -20
- data/lib/active_record/relation/merger.rb +0 -1
- data/lib/active_record/relation/predicate_builder.rb +1 -22
- data/lib/active_record/relation/predicate_builder/array_handler.rb +16 -11
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +0 -4
- data/lib/active_record/relation/query_methods.rb +98 -62
- data/lib/active_record/relation/spawn_methods.rb +6 -7
- data/lib/active_record/result.rb +16 -9
- data/lib/active_record/sanitization.rb +8 -1
- data/lib/active_record/schema.rb +0 -1
- data/lib/active_record/schema_dumper.rb +51 -9
- data/lib/active_record/schema_migration.rb +4 -0
- data/lib/active_record/scoping/default.rb +5 -4
- data/lib/active_record/serializers/xml_serializer.rb +3 -7
- data/lib/active_record/statement_cache.rb +79 -5
- data/lib/active_record/store.rb +5 -5
- data/lib/active_record/tasks/database_tasks.rb +37 -5
- data/lib/active_record/tasks/mysql_database_tasks.rb +10 -16
- data/lib/active_record/tasks/postgresql_database_tasks.rb +2 -2
- data/lib/active_record/timestamp.rb +9 -7
- data/lib/active_record/transactions.rb +35 -21
- data/lib/active_record/type.rb +20 -0
- data/lib/active_record/type/binary.rb +40 -0
- data/lib/active_record/type/boolean.rb +19 -0
- data/lib/active_record/type/date.rb +46 -0
- data/lib/active_record/type/date_time.rb +43 -0
- data/lib/active_record/type/decimal.rb +40 -0
- data/lib/active_record/type/decimal_without_scale.rb +11 -0
- data/lib/active_record/type/float.rb +19 -0
- data/lib/active_record/type/hash_lookup_type_map.rb +19 -0
- data/lib/active_record/type/integer.rb +23 -0
- data/lib/active_record/type/mutable.rb +16 -0
- data/lib/active_record/type/numeric.rb +36 -0
- data/lib/active_record/type/serialized.rb +51 -0
- data/lib/active_record/type/string.rb +36 -0
- data/lib/active_record/type/text.rb +11 -0
- data/lib/active_record/type/time.rb +26 -0
- data/lib/active_record/type/time_value.rb +38 -0
- data/lib/active_record/type/type_map.rb +48 -0
- data/lib/active_record/type/value.rb +101 -0
- data/lib/active_record/validations.rb +21 -16
- data/lib/active_record/validations/uniqueness.rb +9 -23
- data/lib/rails/generators/active_record/migration/migration_generator.rb +8 -4
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +1 -1
- data/lib/rails/generators/active_record/model/templates/model.rb +1 -1
- metadata +71 -14
- data/lib/active_record/connection_adapters/postgresql/cast.rb +0 -168
@@ -11,6 +11,15 @@ module ActiveRecord
|
|
11
11
|
# If the passed hash responds to <tt>permitted?</tt> method and the return value
|
12
12
|
# of this method is +false+ an <tt>ActiveModel::ForbiddenAttributesError</tt>
|
13
13
|
# exception is raised.
|
14
|
+
#
|
15
|
+
# cat = Cat.new(name: "Gorby", status: "yawning")
|
16
|
+
# cat.attributes # => { "name" => "Gorby", "status" => "yawning", "created_at" => nil, "updated_at" => nil}
|
17
|
+
# cat.assign_attributes(status: "sleeping")
|
18
|
+
# cat.attributes # => { "name" => "Gorby", "status" => "sleeping", "created_at" => nil, "updated_at" => nil }
|
19
|
+
#
|
20
|
+
# New attributes will be persisted in the database when the object is saved.
|
21
|
+
#
|
22
|
+
# Aliased to <tt>attributes=</tt>.
|
14
23
|
def assign_attributes(new_attributes)
|
15
24
|
if !new_attributes.respond_to?(:stringify_keys)
|
16
25
|
raise ArgumentError, "When assigning attributes, you must pass a hash as an argument."
|
@@ -43,7 +52,7 @@ module ActiveRecord
|
|
43
52
|
|
44
53
|
def _assign_attribute(k, v)
|
45
54
|
public_send("#{k}=", v)
|
46
|
-
rescue NoMethodError
|
55
|
+
rescue NoMethodError
|
47
56
|
if respond_to?("#{k}=")
|
48
57
|
raise
|
49
58
|
else
|
@@ -106,7 +115,7 @@ module ActiveRecord
|
|
106
115
|
end
|
107
116
|
|
108
117
|
class MultiparameterAttribute #:nodoc:
|
109
|
-
attr_reader :object, :name, :values, :
|
118
|
+
attr_reader :object, :name, :values, :cast_type
|
110
119
|
|
111
120
|
def initialize(object, name, values)
|
112
121
|
@object = object
|
@@ -117,22 +126,22 @@ module ActiveRecord
|
|
117
126
|
def read_value
|
118
127
|
return if values.values.compact.empty?
|
119
128
|
|
120
|
-
@
|
121
|
-
klass
|
129
|
+
@cast_type = object.type_for_attribute(name)
|
130
|
+
klass = cast_type.klass
|
122
131
|
|
123
132
|
if klass == Time
|
124
133
|
read_time
|
125
134
|
elsif klass == Date
|
126
135
|
read_date
|
127
136
|
else
|
128
|
-
read_other
|
137
|
+
read_other
|
129
138
|
end
|
130
139
|
end
|
131
140
|
|
132
141
|
private
|
133
142
|
|
134
143
|
def instantiate_time_object(set_values)
|
135
|
-
if object.class.send(:create_time_zone_conversion_attribute?, name,
|
144
|
+
if object.class.send(:create_time_zone_conversion_attribute?, name, cast_type)
|
136
145
|
Time.zone.local(*set_values)
|
137
146
|
else
|
138
147
|
Time.send(object.class.default_timezone, *set_values)
|
@@ -140,9 +149,9 @@ module ActiveRecord
|
|
140
149
|
end
|
141
150
|
|
142
151
|
def read_time
|
143
|
-
# If column is a :time (and not :date or :
|
152
|
+
# If column is a :time (and not :date or :datetime) there is no need to validate if
|
144
153
|
# there are year/month/day fields
|
145
|
-
if
|
154
|
+
if cast_type.type == :time
|
146
155
|
# if the column is a time set the values to their defaults as January 1, 1970, but only if they're nil
|
147
156
|
{ 1 => 1970, 2 => 1, 3 => 1 }.each do |key,value|
|
148
157
|
values[key] ||= value
|
@@ -172,13 +181,12 @@ module ActiveRecord
|
|
172
181
|
end
|
173
182
|
end
|
174
183
|
|
175
|
-
def read_other
|
184
|
+
def read_other
|
176
185
|
max_position = extract_max_param
|
177
186
|
positions = (1..max_position)
|
178
187
|
validate_required_parameters!(positions)
|
179
188
|
|
180
|
-
|
181
|
-
klass.new(*set_values)
|
189
|
+
values.slice(*positions)
|
182
190
|
end
|
183
191
|
|
184
192
|
# Checks whether some blank date parameter exists. Note that this is different
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module AttributeDecorators # :nodoc:
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
class_attribute :attribute_type_decorations, instance_accessor: false # :internal:
|
7
|
+
self.attribute_type_decorations = TypeDecorator.new
|
8
|
+
end
|
9
|
+
|
10
|
+
module ClassMethods # :nodoc:
|
11
|
+
def decorate_attribute_type(column_name, decorator_name, &block)
|
12
|
+
matcher = ->(name, _) { name == column_name.to_s }
|
13
|
+
key = "_#{column_name}_#{decorator_name}"
|
14
|
+
decorate_matching_attribute_types(matcher, key, &block)
|
15
|
+
end
|
16
|
+
|
17
|
+
def decorate_matching_attribute_types(matcher, decorator_name, &block)
|
18
|
+
clear_caches_calculated_from_columns
|
19
|
+
decorator_name = decorator_name.to_s
|
20
|
+
|
21
|
+
# Create new hashes so we don't modify parent classes
|
22
|
+
self.attribute_type_decorations = attribute_type_decorations.merge(decorator_name => [matcher, block])
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def add_user_provided_columns(*)
|
28
|
+
super.map do |column|
|
29
|
+
decorated_type = attribute_type_decorations.apply(column.name, column.cast_type)
|
30
|
+
column.with_type(decorated_type)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class TypeDecorator # :nodoc:
|
36
|
+
delegate :clear, to: :@decorations
|
37
|
+
|
38
|
+
def initialize(decorations = {})
|
39
|
+
@decorations = decorations
|
40
|
+
end
|
41
|
+
|
42
|
+
def merge(*args)
|
43
|
+
TypeDecorator.new(@decorations.merge(*args))
|
44
|
+
end
|
45
|
+
|
46
|
+
def apply(name, type)
|
47
|
+
decorations = decorators_for(name, type)
|
48
|
+
decorations.inject(type) do |new_type, block|
|
49
|
+
block.call(new_type)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
def decorators_for(name, type)
|
56
|
+
matching(name, type).map(&:last)
|
57
|
+
end
|
58
|
+
|
59
|
+
def matching(name, type)
|
60
|
+
@decorations.values.select do |(matcher, _)|
|
61
|
+
matcher.call(name, type)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -18,6 +18,8 @@ module ActiveRecord
|
|
18
18
|
include TimeZoneConversion
|
19
19
|
include Dirty
|
20
20
|
include Serialization
|
21
|
+
|
22
|
+
delegate :column_for_attribute, to: :class
|
21
23
|
end
|
22
24
|
|
23
25
|
AttrNames = Module.new {
|
@@ -29,7 +31,7 @@ module ActiveRecord
|
|
29
31
|
end
|
30
32
|
}
|
31
33
|
|
32
|
-
BLACKLISTED_CLASS_METHODS = %w(private public protected
|
34
|
+
BLACKLISTED_CLASS_METHODS = %w(private public protected)
|
33
35
|
|
34
36
|
class AttributeMethodCache
|
35
37
|
def initialize
|
@@ -48,7 +50,11 @@ module ActiveRecord
|
|
48
50
|
end
|
49
51
|
|
50
52
|
private
|
51
|
-
|
53
|
+
|
54
|
+
# Override this method in the subclasses for method body.
|
55
|
+
def method_body(method_name, const_name)
|
56
|
+
raise NotImplementedError, "Subclasses must implement a method_body(method_name, const_name) method."
|
57
|
+
end
|
52
58
|
end
|
53
59
|
|
54
60
|
class GeneratedAttributeMethods < Module; end # :nodoc:
|
@@ -63,15 +69,13 @@ module ActiveRecord
|
|
63
69
|
@generated_attribute_methods = GeneratedAttributeMethods.new { extend Mutex_m }
|
64
70
|
@attribute_methods_generated = false
|
65
71
|
include @generated_attribute_methods
|
66
|
-
|
67
|
-
super
|
68
72
|
end
|
69
73
|
|
70
74
|
# Generates all the attribute related methods for columns in the database
|
71
75
|
# accessors, mutators and query methods.
|
72
76
|
def define_attribute_methods # :nodoc:
|
73
77
|
return false if @attribute_methods_generated
|
74
|
-
# Use a mutex; we don't want two
|
78
|
+
# Use a mutex; we don't want two threads simultaneously trying to define
|
75
79
|
# attribute methods.
|
76
80
|
generated_attribute_methods.synchronize do
|
77
81
|
return false if @attribute_methods_generated
|
@@ -84,7 +88,7 @@ module ActiveRecord
|
|
84
88
|
|
85
89
|
def undefine_attribute_methods # :nodoc:
|
86
90
|
generated_attribute_methods.synchronize do
|
87
|
-
super if
|
91
|
+
super if @attribute_methods_generated
|
88
92
|
@attribute_methods_generated = false
|
89
93
|
end
|
90
94
|
end
|
@@ -105,7 +109,7 @@ module ActiveRecord
|
|
105
109
|
# # => false
|
106
110
|
def instance_method_already_implemented?(method_name)
|
107
111
|
if dangerous_attribute_method?(method_name)
|
108
|
-
raise DangerousAttributeError, "#{method_name} is defined by Active Record
|
112
|
+
raise DangerousAttributeError, "#{method_name} is defined by Active Record"
|
109
113
|
end
|
110
114
|
|
111
115
|
if superclass == Base
|
@@ -155,16 +159,6 @@ module ActiveRecord
|
|
155
159
|
end
|
156
160
|
end
|
157
161
|
|
158
|
-
def find_generated_attribute_method(method_name) # :nodoc:
|
159
|
-
klass = self
|
160
|
-
until klass == Base
|
161
|
-
gen_methods = klass.generated_attribute_methods
|
162
|
-
return gen_methods.instance_method(method_name) if method_defined_within?(method_name, gen_methods, Object)
|
163
|
-
klass = klass.superclass
|
164
|
-
end
|
165
|
-
nil
|
166
|
-
end
|
167
|
-
|
168
162
|
# Returns +true+ if +attribute+ is an attribute method and table exists,
|
169
163
|
# +false+ otherwise.
|
170
164
|
#
|
@@ -193,24 +187,29 @@ module ActiveRecord
|
|
193
187
|
[]
|
194
188
|
end
|
195
189
|
end
|
196
|
-
end
|
197
190
|
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
191
|
+
# Returns the column object for the named attribute.
|
192
|
+
# Returns nil if the named attribute does not exist.
|
193
|
+
#
|
194
|
+
# class Person < ActiveRecord::Base
|
195
|
+
# end
|
196
|
+
#
|
197
|
+
# person = Person.new
|
198
|
+
# person.column_for_attribute(:name) # the result depends on the ConnectionAdapter
|
199
|
+
# # => #<ActiveRecord::ConnectionAdapters::Column:0x007ff4ab083980 @name="name", @sql_type="varchar(255)", @null=true, ...>
|
200
|
+
#
|
201
|
+
# person.column_for_attribute(:nothing)
|
202
|
+
# # => nil
|
203
|
+
def column_for_attribute(name)
|
204
|
+
column = columns_hash[name.to_s]
|
205
|
+
if column.nil?
|
206
|
+
ActiveSupport::Deprecation.warn(<<-MESSAGE.strip_heredoc)
|
207
|
+
`column_for_attribute` will return a null object for non-existent columns
|
208
|
+
in Rails 5.0. Use `has_attribute?` if you need to check for an
|
209
|
+
attribute's existence.
|
210
|
+
MESSAGE
|
211
211
|
end
|
212
|
-
|
213
|
-
super
|
212
|
+
column
|
214
213
|
end
|
215
214
|
end
|
216
215
|
|
@@ -231,18 +230,14 @@ module ActiveRecord
|
|
231
230
|
# person.respond_to('age?') # => true
|
232
231
|
# person.respond_to(:nothing) # => false
|
233
232
|
def respond_to?(name, include_private = false)
|
233
|
+
return false unless super
|
234
234
|
name = name.to_s
|
235
|
-
self.class.define_attribute_methods
|
236
|
-
result = super
|
237
|
-
|
238
|
-
# If the result is false the answer is false.
|
239
|
-
return false unless result
|
240
235
|
|
241
236
|
# If the result is true then check for the select case.
|
242
237
|
# For queries selecting a subset of columns, return false for unselected columns.
|
243
238
|
# We check defined?(@attributes) not to issue warnings if called on objects that
|
244
239
|
# have been allocated but not yet initialized.
|
245
|
-
if defined?(@attributes) &&
|
240
|
+
if defined?(@attributes) && self.class.column_names.include?(name)
|
246
241
|
return has_attribute?(name)
|
247
242
|
end
|
248
243
|
|
@@ -259,7 +254,7 @@ module ActiveRecord
|
|
259
254
|
# person.has_attribute?('age') # => true
|
260
255
|
# person.has_attribute?(:nothing) # => false
|
261
256
|
def has_attribute?(attr_name)
|
262
|
-
@attributes.
|
257
|
+
@attributes.key?(attr_name.to_s)
|
263
258
|
end
|
264
259
|
|
265
260
|
# Returns an array of names for the attributes available on this object.
|
@@ -283,20 +278,13 @@ module ActiveRecord
|
|
283
278
|
# person.attributes
|
284
279
|
# # => {"id"=>3, "created_at"=>Sun, 21 Oct 2012 04:53:04, "updated_at"=>Sun, 21 Oct 2012 04:53:04, "name"=>"Francesco", "age"=>22}
|
285
280
|
def attributes
|
286
|
-
|
287
|
-
attrs[name] = read_attribute(name)
|
288
|
-
}
|
289
|
-
end
|
290
|
-
|
291
|
-
# Placeholder so it can be overriden when needed by serialization
|
292
|
-
def attributes_for_coder # :nodoc:
|
293
|
-
attributes
|
281
|
+
@attributes.to_hash
|
294
282
|
end
|
295
283
|
|
296
284
|
# Returns an <tt>#inspect</tt>-like string for the value of the
|
297
|
-
# attribute +attr_name+. String attributes are truncated
|
285
|
+
# attribute +attr_name+. String attributes are truncated up to 50
|
298
286
|
# characters, Date and Time attributes are returned in the
|
299
|
-
# <tt>:db</tt> format, Array attributes are truncated
|
287
|
+
# <tt>:db</tt> format, Array attributes are truncated up to 10 values.
|
300
288
|
# Other attributes return the value of <tt>#inspect</tt> without
|
301
289
|
# modification.
|
302
290
|
#
|
@@ -333,39 +321,24 @@ module ActiveRecord
|
|
333
321
|
# class Task < ActiveRecord::Base
|
334
322
|
# end
|
335
323
|
#
|
336
|
-
#
|
337
|
-
#
|
338
|
-
#
|
339
|
-
#
|
340
|
-
#
|
341
|
-
#
|
342
|
-
#
|
324
|
+
# task = Task.new(title: '', is_done: false)
|
325
|
+
# task.attribute_present?(:title) # => false
|
326
|
+
# task.attribute_present?(:is_done) # => true
|
327
|
+
# task.title = 'Buy milk'
|
328
|
+
# task.is_done = true
|
329
|
+
# task.attribute_present?(:title) # => true
|
330
|
+
# task.attribute_present?(:is_done) # => true
|
343
331
|
def attribute_present?(attribute)
|
344
332
|
value = read_attribute(attribute)
|
345
333
|
!value.nil? && !(value.respond_to?(:empty?) && value.empty?)
|
346
334
|
end
|
347
335
|
|
348
|
-
# Returns the column object for the named attribute. Returns +nil+ if the
|
349
|
-
# named attribute not exists.
|
350
|
-
#
|
351
|
-
# class Person < ActiveRecord::Base
|
352
|
-
# end
|
353
|
-
#
|
354
|
-
# person = Person.new
|
355
|
-
# person.column_for_attribute(:name) # the result depends on the ConnectionAdapter
|
356
|
-
# # => #<ActiveRecord::ConnectionAdapters::SQLite3Column:0x007ff4ab083980 @name="name", @sql_type="varchar(255)", @null=true, ...>
|
357
|
-
#
|
358
|
-
# person.column_for_attribute(:nothing)
|
359
|
-
# # => nil
|
360
|
-
def column_for_attribute(name)
|
361
|
-
# FIXME: should this return a null object for columns that don't exist?
|
362
|
-
self.class.columns_hash[name.to_s]
|
363
|
-
end
|
364
|
-
|
365
336
|
# Returns the value of the attribute identified by <tt>attr_name</tt> after it has been typecast (for example,
|
366
337
|
# "2004-12-12" in a date column is cast to a date object, like Date.new(2004, 12, 12)). It raises
|
367
338
|
# <tt>ActiveModel::MissingAttributeError</tt> if the identified attribute is missing.
|
368
339
|
#
|
340
|
+
# Note: +:id+ is always present.
|
341
|
+
#
|
369
342
|
# Alias for the <tt>read_attribute</tt> method.
|
370
343
|
#
|
371
344
|
# class Person < ActiveRecord::Base
|
@@ -399,13 +372,6 @@ module ActiveRecord
|
|
399
372
|
|
400
373
|
protected
|
401
374
|
|
402
|
-
def clone_attributes(reader_method = :read_attribute, attributes = {}) # :nodoc:
|
403
|
-
attribute_names.each do |name|
|
404
|
-
attributes[name] = clone_attribute_value(reader_method, name)
|
405
|
-
end
|
406
|
-
attributes
|
407
|
-
end
|
408
|
-
|
409
375
|
def clone_attribute_value(reader_method, attribute_name) # :nodoc:
|
410
376
|
value = send(reader_method, attribute_name)
|
411
377
|
value.duplicable? ? value.clone : value
|
@@ -423,7 +389,7 @@ module ActiveRecord
|
|
423
389
|
|
424
390
|
def attribute_method?(attr_name) # :nodoc:
|
425
391
|
# We check defined? because Syck calls respond_to? before actually calling initialize.
|
426
|
-
defined?(@attributes) && @attributes.
|
392
|
+
defined?(@attributes) && @attributes.key?(attr_name)
|
427
393
|
end
|
428
394
|
|
429
395
|
private
|
@@ -442,16 +408,16 @@ module ActiveRecord
|
|
442
408
|
|
443
409
|
# Filters the primary keys and readonly attributes from the attribute names.
|
444
410
|
def attributes_for_update(attribute_names)
|
445
|
-
attribute_names.
|
446
|
-
|
411
|
+
attribute_names.reject do |name|
|
412
|
+
readonly_attribute?(name)
|
447
413
|
end
|
448
414
|
end
|
449
415
|
|
450
416
|
# Filters out the primary keys, from the attribute names, when the primary
|
451
417
|
# key is to be generated (e.g. the id attribute has no value).
|
452
418
|
def attributes_for_create(attribute_names)
|
453
|
-
attribute_names.
|
454
|
-
|
419
|
+
attribute_names.reject do |name|
|
420
|
+
pk_attribute?(name) && id.nil?
|
455
421
|
end
|
456
422
|
end
|
457
423
|
|
@@ -460,13 +426,10 @@ module ActiveRecord
|
|
460
426
|
end
|
461
427
|
|
462
428
|
def pk_attribute?(name)
|
463
|
-
|
429
|
+
name == self.class.primary_key
|
464
430
|
end
|
465
431
|
|
466
432
|
def typecasted_attribute_value(name)
|
467
|
-
# FIXME: we need @attributes to be used consistently.
|
468
|
-
# If the values stored in @attributes were already typecasted, this code
|
469
|
-
# could be simplified
|
470
433
|
read_attribute(name)
|
471
434
|
end
|
472
435
|
end
|
@@ -43,7 +43,7 @@ module ActiveRecord
|
|
43
43
|
# task.read_attribute_before_type_cast('completed_on') # => "2012-10-21"
|
44
44
|
# task.read_attribute_before_type_cast(:completed_on) # => "2012-10-21"
|
45
45
|
def read_attribute_before_type_cast(attr_name)
|
46
|
-
@attributes[attr_name.to_s]
|
46
|
+
@attributes[attr_name.to_s].value_before_type_cast
|
47
47
|
end
|
48
48
|
|
49
49
|
# Returns a hash of attributes before typecasting and deserialization.
|
@@ -57,7 +57,7 @@ module ActiveRecord
|
|
57
57
|
# task.attributes_before_type_cast
|
58
58
|
# # => {"id"=>nil, "title"=>nil, "is_done"=>true, "completed_on"=>"2012-10-21", "created_at"=>nil, "updated_at"=>nil}
|
59
59
|
def attributes_before_type_cast
|
60
|
-
@attributes
|
60
|
+
@attributes.values_before_type_cast
|
61
61
|
end
|
62
62
|
|
63
63
|
private
|