activerecord 4.1.15 → 4.2.11.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +5 -5
- data/CHANGELOG.md +1162 -1792
- data/README.rdoc +15 -10
- data/lib/active_record.rb +4 -0
- data/lib/active_record/aggregations.rb +15 -8
- data/lib/active_record/association_relation.rb +13 -0
- data/lib/active_record/associations.rb +158 -49
- data/lib/active_record/associations/alias_tracker.rb +3 -12
- data/lib/active_record/associations/association.rb +16 -4
- data/lib/active_record/associations/association_scope.rb +83 -38
- data/lib/active_record/associations/belongs_to_association.rb +28 -10
- data/lib/active_record/associations/builder/association.rb +15 -4
- data/lib/active_record/associations/builder/belongs_to.rb +7 -29
- data/lib/active_record/associations/builder/collection_association.rb +5 -1
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +8 -13
- data/lib/active_record/associations/builder/has_many.rb +1 -1
- 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 +63 -27
- data/lib/active_record/associations/collection_proxy.rb +29 -35
- data/lib/active_record/associations/foreign_association.rb +11 -0
- data/lib/active_record/associations/has_many_association.rb +83 -22
- data/lib/active_record/associations/has_many_through_association.rb +49 -26
- data/lib/active_record/associations/has_one_association.rb +1 -1
- data/lib/active_record/associations/join_dependency.rb +26 -13
- data/lib/active_record/associations/join_dependency/join_association.rb +25 -15
- data/lib/active_record/associations/join_dependency/join_part.rb +0 -1
- data/lib/active_record/associations/preloader.rb +36 -26
- data/lib/active_record/associations/preloader/association.rb +14 -11
- data/lib/active_record/associations/preloader/through_association.rb +4 -3
- data/lib/active_record/associations/singular_association.rb +17 -2
- data/lib/active_record/associations/through_association.rb +5 -12
- data/lib/active_record/attribute.rb +163 -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 +56 -94
- data/lib/active_record/attribute_methods/before_type_cast.rb +7 -2
- data/lib/active_record/attribute_methods/dirty.rb +107 -43
- data/lib/active_record/attribute_methods/primary_key.rb +7 -8
- data/lib/active_record/attribute_methods/query.rb +1 -1
- data/lib/active_record/attribute_methods/read.rb +22 -59
- data/lib/active_record/attribute_methods/serialization.rb +16 -150
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +38 -40
- data/lib/active_record/attribute_methods/write.rb +9 -24
- data/lib/active_record/attribute_set.rb +81 -0
- data/lib/active_record/attribute_set/builder.rb +106 -0
- data/lib/active_record/attributes.rb +147 -0
- data/lib/active_record/autosave_association.rb +19 -12
- data/lib/active_record/base.rb +13 -24
- data/lib/active_record/callbacks.rb +6 -6
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +84 -52
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +52 -50
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/quoting.rb +60 -60
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +39 -4
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +138 -56
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -34
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +268 -71
- data/lib/active_record/connection_adapters/abstract/transaction.rb +125 -118
- data/lib/active_record/connection_adapters/abstract_adapter.rb +171 -59
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +293 -139
- data/lib/active_record/connection_adapters/column.rb +29 -240
- data/lib/active_record/connection_adapters/connection_specification.rb +15 -24
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +16 -32
- data/lib/active_record/connection_adapters/mysql_adapter.rb +67 -144
- 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 +40 -25
- data/lib/active_record/connection_adapters/postgresql/oid.rb +29 -388
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +100 -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 +15 -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 +36 -0
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +19 -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 +79 -0
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +19 -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 +109 -0
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +21 -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 +46 -136
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +4 -4
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +152 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +131 -43
- data/lib/active_record/connection_adapters/postgresql/utils.rb +77 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +224 -477
- data/lib/active_record/connection_adapters/schema_cache.rb +14 -28
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +61 -75
- data/lib/active_record/connection_handling.rb +1 -1
- data/lib/active_record/core.rb +163 -39
- data/lib/active_record/counter_cache.rb +60 -6
- data/lib/active_record/enum.rb +9 -11
- data/lib/active_record/errors.rb +53 -30
- data/lib/active_record/explain.rb +1 -1
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixtures.rb +55 -69
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +35 -10
- data/lib/active_record/integration.rb +4 -4
- data/lib/active_record/legacy_yaml_adapter.rb +30 -0
- data/lib/active_record/locking/optimistic.rb +46 -26
- data/lib/active_record/migration.rb +71 -46
- 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 +52 -58
- data/lib/active_record/nested_attributes.rb +5 -5
- data/lib/active_record/no_touching.rb +1 -1
- data/lib/active_record/persistence.rb +46 -26
- data/lib/active_record/query_cache.rb +3 -3
- data/lib/active_record/querying.rb +10 -7
- data/lib/active_record/railtie.rb +18 -11
- data/lib/active_record/railties/databases.rake +50 -51
- data/lib/active_record/readonly_attributes.rb +0 -1
- data/lib/active_record/reflection.rb +273 -114
- data/lib/active_record/relation.rb +57 -25
- data/lib/active_record/relation/batches.rb +0 -2
- data/lib/active_record/relation/calculations.rb +41 -37
- data/lib/active_record/relation/finder_methods.rb +70 -47
- data/lib/active_record/relation/merger.rb +39 -29
- data/lib/active_record/relation/predicate_builder.rb +16 -8
- data/lib/active_record/relation/predicate_builder/array_handler.rb +32 -13
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -5
- data/lib/active_record/relation/query_methods.rb +114 -65
- data/lib/active_record/relation/spawn_methods.rb +3 -0
- data/lib/active_record/result.rb +18 -7
- data/lib/active_record/sanitization.rb +12 -2
- data/lib/active_record/schema.rb +0 -1
- data/lib/active_record/schema_dumper.rb +59 -28
- data/lib/active_record/schema_migration.rb +5 -4
- data/lib/active_record/scoping/default.rb +6 -4
- data/lib/active_record/scoping/named.rb +4 -0
- data/lib/active_record/serializers/xml_serializer.rb +3 -7
- data/lib/active_record/statement_cache.rb +95 -10
- data/lib/active_record/store.rb +5 -5
- data/lib/active_record/tasks/database_tasks.rb +61 -6
- data/lib/active_record/tasks/mysql_database_tasks.rb +32 -17
- data/lib/active_record/tasks/postgresql_database_tasks.rb +20 -9
- data/lib/active_record/timestamp.rb +9 -7
- data/lib/active_record/transactions.rb +53 -27
- data/lib/active_record/type.rb +23 -0
- data/lib/active_record/type/big_integer.rb +13 -0
- data/lib/active_record/type/binary.rb +50 -0
- data/lib/active_record/type/boolean.rb +31 -0
- data/lib/active_record/type/date.rb +50 -0
- data/lib/active_record/type/date_time.rb +54 -0
- data/lib/active_record/type/decimal.rb +64 -0
- data/lib/active_record/type/decimal_without_scale.rb +11 -0
- data/lib/active_record/type/decorator.rb +14 -0
- data/lib/active_record/type/float.rb +19 -0
- data/lib/active_record/type/hash_lookup_type_map.rb +23 -0
- data/lib/active_record/type/integer.rb +59 -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 +62 -0
- data/lib/active_record/type/string.rb +40 -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 +64 -0
- data/lib/active_record/type/unsigned_integer.rb +15 -0
- data/lib/active_record/type/value.rb +110 -0
- data/lib/active_record/validations.rb +25 -19
- data/lib/active_record/validations/associated.rb +5 -3
- data/lib/active_record/validations/presence.rb +5 -3
- data/lib/active_record/validations/uniqueness.rb +25 -29
- 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 +66 -11
- data/lib/active_record/connection_adapters/postgresql/cast.rb +0 -168
@@ -74,7 +74,9 @@ module ActiveRecord
|
|
74
74
|
:rename_index, :rename_column, :add_index, :remove_index, :add_timestamps, :remove_timestamps,
|
75
75
|
:change_column_default, :add_reference, :remove_reference, :transaction,
|
76
76
|
:drop_join_table, :drop_table, :execute_block, :enable_extension,
|
77
|
-
:change_column, :execute, :remove_columns, :change_column_null
|
77
|
+
:change_column, :execute, :remove_columns, :change_column_null,
|
78
|
+
:add_foreign_key, :remove_foreign_key
|
79
|
+
# irreversible methods need to be here too
|
78
80
|
].each do |method|
|
79
81
|
class_eval <<-EOV, __FILE__, __LINE__ + 1
|
80
82
|
def #{method}(*args, &block) # def create_table(*args, &block)
|
@@ -85,7 +87,7 @@ module ActiveRecord
|
|
85
87
|
alias :add_belongs_to :add_reference
|
86
88
|
alias :remove_belongs_to :remove_reference
|
87
89
|
|
88
|
-
def change_table(table_name, options = {})
|
90
|
+
def change_table(table_name, options = {}) # :nodoc:
|
89
91
|
yield delegate.update_table_definition(table_name, self)
|
90
92
|
end
|
91
93
|
|
@@ -167,6 +169,21 @@ module ActiveRecord
|
|
167
169
|
[:change_column_null, args]
|
168
170
|
end
|
169
171
|
|
172
|
+
def invert_add_foreign_key(args)
|
173
|
+
from_table, to_table, add_options = args
|
174
|
+
add_options ||= {}
|
175
|
+
|
176
|
+
if add_options[:name]
|
177
|
+
options = { name: add_options[:name] }
|
178
|
+
elsif add_options[:column]
|
179
|
+
options = { column: add_options[:column] }
|
180
|
+
else
|
181
|
+
options = to_table
|
182
|
+
end
|
183
|
+
|
184
|
+
[:remove_foreign_key, [from_table, options]]
|
185
|
+
end
|
186
|
+
|
170
187
|
# Forwards any missing method call to the \target.
|
171
188
|
def method_missing(method, *args, &block)
|
172
189
|
if @delegate.respond_to?(method)
|
@@ -29,6 +29,10 @@ module ActiveRecord
|
|
29
29
|
# :singleton-method:
|
30
30
|
# Works like +table_name_prefix+, but appends instead of prepends (set to "_basecamp" gives "projects_basecamp",
|
31
31
|
# "people_basecamp"). By default, the suffix is the empty string.
|
32
|
+
#
|
33
|
+
# If you are organising your models within modules, you can add a suffix to the models within
|
34
|
+
# a namespace by defining a singleton method in the parent module called table_name_suffix which
|
35
|
+
# returns your chosen suffix.
|
32
36
|
class_attribute :table_name_suffix, instance_writer: false
|
33
37
|
self.table_name_suffix = ""
|
34
38
|
|
@@ -47,6 +51,19 @@ module ActiveRecord
|
|
47
51
|
self.pluralize_table_names = true
|
48
52
|
|
49
53
|
self.inheritance_column = 'type'
|
54
|
+
|
55
|
+
delegate :type_for_attribute, to: :class
|
56
|
+
end
|
57
|
+
|
58
|
+
# Derives the join table name for +first_table+ and +second_table+. The
|
59
|
+
# table names appear in alphabetical order. A common prefix is removed
|
60
|
+
# (useful for namespaced models like Music::Artist and Music::Record):
|
61
|
+
#
|
62
|
+
# artists, records => artists_records
|
63
|
+
# records, artists => artists_records
|
64
|
+
# music_artists, music_records => music_artists_records
|
65
|
+
def self.derive_join_table_name(first_table, second_table) # :nodoc:
|
66
|
+
[first_table.to_s, second_table.to_s].sort.join("\0").gsub(/^(.*_)(.+)\0\1(.+)/, '\1\2_\3').tr("\0", "_")
|
50
67
|
end
|
51
68
|
|
52
69
|
module ClassMethods
|
@@ -153,6 +170,10 @@ module ActiveRecord
|
|
153
170
|
(parents.detect{ |p| p.respond_to?(:table_name_prefix) } || self).table_name_prefix
|
154
171
|
end
|
155
172
|
|
173
|
+
def full_table_name_suffix #:nodoc:
|
174
|
+
(parents.detect {|p| p.respond_to?(:table_name_suffix) } || self).table_name_suffix
|
175
|
+
end
|
176
|
+
|
156
177
|
# Defines the name of the table column which will store the class name on single-table
|
157
178
|
# inheritance situations.
|
158
179
|
#
|
@@ -190,7 +211,7 @@ module ActiveRecord
|
|
190
211
|
# given block. This is required for Oracle and is useful for any
|
191
212
|
# database which relies on sequences for primary key generation.
|
192
213
|
#
|
193
|
-
# If a sequence name is not explicitly set when using Oracle
|
214
|
+
# If a sequence name is not explicitly set when using Oracle,
|
194
215
|
# it will default to the commonly used pattern of: #{table_name}_seq
|
195
216
|
#
|
196
217
|
# If a sequence name is not explicitly set when using PostgreSQL, it
|
@@ -209,50 +230,29 @@ module ActiveRecord
|
|
209
230
|
connection.schema_cache.table_exists?(table_name)
|
210
231
|
end
|
211
232
|
|
212
|
-
|
213
|
-
|
214
|
-
@columns ||= connection.schema_cache.columns(table_name).map do |col|
|
215
|
-
col = col.dup
|
216
|
-
col.primary = (col.name == primary_key)
|
217
|
-
col
|
218
|
-
end
|
219
|
-
end
|
220
|
-
|
221
|
-
# Returns a hash of column objects for the table associated with this class.
|
222
|
-
def columns_hash
|
223
|
-
@columns_hash ||= Hash[columns.map { |c| [c.name, c] }]
|
233
|
+
def attributes_builder # :nodoc:
|
234
|
+
@attributes_builder ||= AttributeSet::Builder.new(column_types, primary_key)
|
224
235
|
end
|
225
236
|
|
226
237
|
def column_types # :nodoc:
|
227
|
-
@column_types ||=
|
228
|
-
|
229
|
-
|
230
|
-
def decorate_columns(columns_hash) # :nodoc:
|
231
|
-
return if columns_hash.empty?
|
232
|
-
|
233
|
-
@serialized_column_names ||= self.columns_hash.keys.find_all do |name|
|
234
|
-
serialized_attributes.key?(name)
|
235
|
-
end
|
236
|
-
|
237
|
-
@serialized_column_names.each do |name|
|
238
|
-
columns_hash[name] = AttributeMethods::Serialization::Type.new(columns_hash[name])
|
239
|
-
end
|
240
|
-
|
241
|
-
@time_zone_column_names ||= self.columns_hash.find_all do |name, col|
|
242
|
-
create_time_zone_conversion_attribute?(name, col)
|
243
|
-
end.map!(&:first)
|
244
|
-
|
245
|
-
@time_zone_column_names.each do |name|
|
246
|
-
columns_hash[name] = AttributeMethods::TimeZoneConversion::Type.new(columns_hash[name])
|
238
|
+
@column_types ||= columns_hash.transform_values(&:cast_type).tap do |h|
|
239
|
+
h.default = Type::Value.new
|
247
240
|
end
|
241
|
+
end
|
248
242
|
|
249
|
-
|
243
|
+
def type_for_attribute(attr_name) # :nodoc:
|
244
|
+
column_types[attr_name]
|
250
245
|
end
|
251
246
|
|
252
247
|
# Returns a hash where the keys are column names and the values are
|
253
248
|
# default values when instantiating the AR object for this table.
|
254
249
|
def column_defaults
|
255
|
-
|
250
|
+
_default_attributes.dup.to_hash
|
251
|
+
end
|
252
|
+
|
253
|
+
def _default_attributes # :nodoc:
|
254
|
+
@default_attributes ||= attributes_builder.build_from_database(
|
255
|
+
raw_default_values)
|
256
256
|
end
|
257
257
|
|
258
258
|
# Returns an array of column names as strings.
|
@@ -263,7 +263,7 @@ module ActiveRecord
|
|
263
263
|
# Returns an array of column objects where the primary id, all columns ending in "_id" or "_count",
|
264
264
|
# and columns used for single table inheritance have been removed.
|
265
265
|
def content_columns
|
266
|
-
@content_columns ||= columns.reject { |c| c.
|
266
|
+
@content_columns ||= columns.reject { |c| c.name == primary_key || c.name =~ /(_id|_count)$/ || c.name == inheritance_column }
|
267
267
|
end
|
268
268
|
|
269
269
|
# Resets all the cached information about columns, which will cause them
|
@@ -295,28 +295,17 @@ module ActiveRecord
|
|
295
295
|
def reset_column_information
|
296
296
|
connection.clear_cache!
|
297
297
|
undefine_attribute_methods
|
298
|
-
connection.schema_cache.clear_table_cache!(table_name)
|
299
|
-
|
300
|
-
@arel_engine
|
301
|
-
@
|
302
|
-
@
|
303
|
-
@
|
304
|
-
@
|
305
|
-
@
|
306
|
-
@
|
307
|
-
@dynamic_methods_hash = nil
|
308
|
-
@inheritance_column = nil unless defined?(@explicit_inheritance_column) && @explicit_inheritance_column
|
309
|
-
@relation = nil
|
310
|
-
@serialized_column_names = nil
|
311
|
-
@time_zone_column_names = nil
|
312
|
-
@cached_time_zone = nil
|
313
|
-
end
|
298
|
+
connection.schema_cache.clear_table_cache!(table_name)
|
299
|
+
|
300
|
+
@arel_engine = nil
|
301
|
+
@column_names = nil
|
302
|
+
@column_types = nil
|
303
|
+
@content_columns = nil
|
304
|
+
@default_attributes = nil
|
305
|
+
@inheritance_column = nil unless defined?(@explicit_inheritance_column) && @explicit_inheritance_column
|
306
|
+
@relation = nil
|
314
307
|
|
315
|
-
|
316
|
-
# attributes when they are initialized. (e.g. attribute
|
317
|
-
# serialization)
|
318
|
-
def initialize_attributes(attributes, options = {}) #:nodoc:
|
319
|
-
attributes
|
308
|
+
initialize_find_by_cache
|
320
309
|
end
|
321
310
|
|
322
311
|
private
|
@@ -337,12 +326,17 @@ module ActiveRecord
|
|
337
326
|
contained = contained.singularize if parent.pluralize_table_names
|
338
327
|
contained += '_'
|
339
328
|
end
|
340
|
-
|
329
|
+
|
330
|
+
"#{full_table_name_prefix}#{contained}#{undecorated_table_name(name)}#{full_table_name_suffix}"
|
341
331
|
else
|
342
332
|
# STI subclasses always use their superclass' table.
|
343
333
|
base.table_name
|
344
334
|
end
|
345
335
|
end
|
336
|
+
|
337
|
+
def raw_default_values
|
338
|
+
columns_hash.transform_values(&:default)
|
339
|
+
end
|
346
340
|
end
|
347
341
|
end
|
348
342
|
end
|
@@ -485,10 +485,10 @@ module ActiveRecord
|
|
485
485
|
end
|
486
486
|
|
487
487
|
# Takes in a limit and checks if the attributes_collection has too many
|
488
|
-
# records.
|
489
|
-
# number-like
|
488
|
+
# records. It accepts limit in the form of symbol, proc, or
|
489
|
+
# number-like object (anything that can be compared with an integer).
|
490
490
|
#
|
491
|
-
#
|
491
|
+
# Raises TooManyRecords error if the attributes_collection is
|
492
492
|
# larger than the limit.
|
493
493
|
def check_record_limit!(limit, attributes_collection)
|
494
494
|
if limit
|
@@ -516,10 +516,10 @@ module ActiveRecord
|
|
516
516
|
|
517
517
|
# Determines if a hash contains a truthy _destroy key.
|
518
518
|
def has_destroy_flag?(hash)
|
519
|
-
|
519
|
+
Type::Boolean.new.type_cast_from_user(hash['_destroy'])
|
520
520
|
end
|
521
521
|
|
522
|
-
# Determines if a new record should be
|
522
|
+
# Determines if a new record should be rejected by checking
|
523
523
|
# has_destroy_flag? or if a <tt>:reject_if</tt> proc exists for this
|
524
524
|
# association and evaluates to +true+.
|
525
525
|
def reject_new_record?(association_name, attributes)
|
@@ -36,6 +36,23 @@ module ActiveRecord
|
|
36
36
|
end
|
37
37
|
end
|
38
38
|
|
39
|
+
# Creates an object (or multiple objects) and saves it to the database,
|
40
|
+
# if validations pass. Raises a RecordInvalid error if validations fail,
|
41
|
+
# unlike Base#create.
|
42
|
+
#
|
43
|
+
# The +attributes+ parameter can be either a Hash or an Array of Hashes.
|
44
|
+
# These describe which attributes to be created on the object, or
|
45
|
+
# multiple objects when given an Array of Hashes.
|
46
|
+
def create!(attributes = nil, &block)
|
47
|
+
if attributes.is_a?(Array)
|
48
|
+
attributes.collect { |attr| create!(attr, &block) }
|
49
|
+
else
|
50
|
+
object = new(attributes, &block)
|
51
|
+
object.save!
|
52
|
+
object
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
39
56
|
# Given an attributes hash, +instantiate+ returns a new instance of
|
40
57
|
# the appropriate class. Accepts only keys as strings.
|
41
58
|
#
|
@@ -48,8 +65,8 @@ module ActiveRecord
|
|
48
65
|
# how this "single-table" inheritance mapping is implemented.
|
49
66
|
def instantiate(attributes, column_types = {})
|
50
67
|
klass = discriminate_class_for_record(attributes)
|
51
|
-
|
52
|
-
klass.allocate.init_with('attributes' => attributes, '
|
68
|
+
attributes = klass.attributes_builder.build_from_database(attributes, column_types)
|
69
|
+
klass.allocate.init_with('attributes' => attributes, 'new_record' => false)
|
53
70
|
end
|
54
71
|
|
55
72
|
private
|
@@ -122,7 +139,7 @@ module ActiveRecord
|
|
122
139
|
# Attributes marked as readonly are silently ignored if the record is
|
123
140
|
# being updated.
|
124
141
|
def save!(*)
|
125
|
-
create_or_update || raise(RecordNotSaved)
|
142
|
+
create_or_update || raise(RecordNotSaved.new("Failed to save the record", self))
|
126
143
|
end
|
127
144
|
|
128
145
|
# Deletes the record in the database and freezes this instance to
|
@@ -149,8 +166,9 @@ module ActiveRecord
|
|
149
166
|
# and <tt>destroy</tt> returns +false+. See
|
150
167
|
# ActiveRecord::Callbacks for further details.
|
151
168
|
def destroy
|
152
|
-
raise ReadOnlyRecord if readonly?
|
169
|
+
raise ReadOnlyRecord, "#{self.class} is marked as readonly" if readonly?
|
153
170
|
destroy_associations
|
171
|
+
self.class.connection.add_transaction_record(self)
|
154
172
|
destroy_row if persisted?
|
155
173
|
@destroyed = true
|
156
174
|
freeze
|
@@ -164,7 +182,7 @@ module ActiveRecord
|
|
164
182
|
# and <tt>destroy!</tt> raises ActiveRecord::RecordNotDestroyed. See
|
165
183
|
# ActiveRecord::Callbacks for further details.
|
166
184
|
def destroy!
|
167
|
-
destroy || raise(
|
185
|
+
destroy || raise(RecordNotDestroyed.new("Failed to destroy the record", self))
|
168
186
|
end
|
169
187
|
|
170
188
|
# Returns an instance of the specified +klass+ with the attributes of the
|
@@ -180,7 +198,6 @@ module ActiveRecord
|
|
180
198
|
def becomes(klass)
|
181
199
|
became = klass.new
|
182
200
|
became.instance_variable_set("@attributes", @attributes)
|
183
|
-
became.instance_variable_set("@attributes_cache", @attributes_cache)
|
184
201
|
changed_attributes = @changed_attributes if defined?(@changed_attributes)
|
185
202
|
became.instance_variable_set("@changed_attributes", changed_attributes || {})
|
186
203
|
became.instance_variable_set("@new_record", new_record?)
|
@@ -215,6 +232,8 @@ module ActiveRecord
|
|
215
232
|
#
|
216
233
|
# This method raises an +ActiveRecord::ActiveRecordError+ if the
|
217
234
|
# attribute is marked as readonly.
|
235
|
+
#
|
236
|
+
# See also +update_column+.
|
218
237
|
def update_attribute(name, value)
|
219
238
|
name = name.to_s
|
220
239
|
verify_readonly_attribute(name)
|
@@ -270,7 +289,8 @@ module ActiveRecord
|
|
270
289
|
# This method raises an +ActiveRecord::ActiveRecordError+ when called on new
|
271
290
|
# objects, or when at least one of the attributes is marked as readonly.
|
272
291
|
def update_columns(attributes)
|
273
|
-
raise ActiveRecordError, "cannot update
|
292
|
+
raise ActiveRecordError, "cannot update a new record" if new_record?
|
293
|
+
raise ActiveRecordError, "cannot update a destroyed record" if destroyed?
|
274
294
|
|
275
295
|
attributes.each_key do |key|
|
276
296
|
verify_readonly_attribute(key.to_s)
|
@@ -349,7 +369,7 @@ module ActiveRecord
|
|
349
369
|
# # => #<Account id: 1, email: 'account@example.com'>
|
350
370
|
#
|
351
371
|
# Attributes are reloaded from the database, and caches busted, in
|
352
|
-
# particular the associations cache.
|
372
|
+
# particular the associations cache and the QueryCache.
|
353
373
|
#
|
354
374
|
# If the record no longer exists in the database <tt>ActiveRecord::RecordNotFound</tt>
|
355
375
|
# is raised. Otherwise, in addition to the in-place modification the method
|
@@ -387,6 +407,7 @@ module ActiveRecord
|
|
387
407
|
def reload(options = nil)
|
388
408
|
clear_aggregation_cache
|
389
409
|
clear_association_cache
|
410
|
+
self.class.connection.clear_query_cache
|
390
411
|
|
391
412
|
fresh_object =
|
392
413
|
if options && options[:lock]
|
@@ -395,25 +416,24 @@ module ActiveRecord
|
|
395
416
|
self.class.unscoped { self.class.find(id) }
|
396
417
|
end
|
397
418
|
|
398
|
-
@attributes
|
399
|
-
|
400
|
-
@column_types = self.class.column_types
|
401
|
-
@column_types_override = fresh_object.instance_variable_get('@column_types_override')
|
402
|
-
@attributes_cache = {}
|
403
|
-
@new_record = false
|
419
|
+
@attributes = fresh_object.instance_variable_get('@attributes')
|
420
|
+
@new_record = false
|
404
421
|
self
|
405
422
|
end
|
406
423
|
|
407
424
|
# Saves the record with the updated_at/on attributes set to the current time.
|
408
425
|
# Please note that no validation is performed and only the +after_touch+,
|
409
426
|
# +after_commit+ and +after_rollback+ callbacks are executed.
|
410
|
-
# If an attribute name is passed, that attribute is updated along with
|
411
|
-
# updated_at/on attributes.
|
412
427
|
#
|
413
|
-
#
|
414
|
-
#
|
428
|
+
# If attribute names are passed, they are updated along with updated_at/on
|
429
|
+
# attributes.
|
430
|
+
#
|
431
|
+
# product.touch # updates updated_at/on
|
432
|
+
# product.touch(:designed_at) # updates the designed_at attribute and updated_at/on
|
433
|
+
# product.touch(:started_at, :ended_at) # updates started_at, ended_at and updated_at/on attributes
|
415
434
|
#
|
416
|
-
# If used along with +belongs_to+ then +touch+ will invoke +touch+ method on
|
435
|
+
# If used along with +belongs_to+ then +touch+ will invoke +touch+ method on
|
436
|
+
# associated object.
|
417
437
|
#
|
418
438
|
# class Brake < ActiveRecord::Base
|
419
439
|
# belongs_to :car, touch: true
|
@@ -432,11 +452,11 @@ module ActiveRecord
|
|
432
452
|
# ball = Ball.new
|
433
453
|
# ball.touch(:updated_at) # => raises ActiveRecordError
|
434
454
|
#
|
435
|
-
def touch(
|
455
|
+
def touch(*names)
|
436
456
|
raise ActiveRecordError, "cannot touch on a new record object" unless persisted?
|
437
457
|
|
438
458
|
attributes = timestamp_attributes_for_update_in_model
|
439
|
-
attributes
|
459
|
+
attributes.concat(names)
|
440
460
|
|
441
461
|
unless attributes.empty?
|
442
462
|
current_time = current_time_from_proper_timezone
|
@@ -449,7 +469,7 @@ module ActiveRecord
|
|
449
469
|
|
450
470
|
changes[self.class.locking_column] = increment_lock if locking_enabled?
|
451
471
|
|
452
|
-
|
472
|
+
clear_attribute_changes(changes.keys)
|
453
473
|
primary_key = self.class.primary_key
|
454
474
|
self.class.unscoped.where(primary_key => self[primary_key]).update_all(changes) == 1
|
455
475
|
else
|
@@ -470,7 +490,7 @@ module ActiveRecord
|
|
470
490
|
def relation_for_destroy
|
471
491
|
pk = self.class.primary_key
|
472
492
|
column = self.class.columns_hash[pk]
|
473
|
-
substitute = self.class.connection.substitute_at(column
|
493
|
+
substitute = self.class.connection.substitute_at(column)
|
474
494
|
|
475
495
|
relation = self.class.unscoped.where(
|
476
496
|
self.class.arel_table[pk].eq(substitute))
|
@@ -480,14 +500,14 @@ module ActiveRecord
|
|
480
500
|
end
|
481
501
|
|
482
502
|
def create_or_update
|
483
|
-
raise ReadOnlyRecord if readonly?
|
503
|
+
raise ReadOnlyRecord, "#{self.class} is marked as readonly" if readonly?
|
484
504
|
result = new_record? ? _create_record : _update_record
|
485
505
|
result != false
|
486
506
|
end
|
487
507
|
|
488
508
|
# Updates the associated record with values matching those of the instance attributes.
|
489
509
|
# Returns the number of affected rows.
|
490
|
-
def _update_record(attribute_names =
|
510
|
+
def _update_record(attribute_names = self.attribute_names)
|
491
511
|
attributes_values = arel_attributes_with_values_for_update(attribute_names)
|
492
512
|
if attributes_values.empty?
|
493
513
|
0
|
@@ -498,7 +518,7 @@ module ActiveRecord
|
|
498
518
|
|
499
519
|
# Creates a record with values matching those of the instance attributes
|
500
520
|
# and returns its id.
|
501
|
-
def _create_record(attribute_names =
|
521
|
+
def _create_record(attribute_names = self.attribute_names)
|
502
522
|
attributes_values = arel_attributes_with_values_for_create(attribute_names)
|
503
523
|
|
504
524
|
new_id = self.class.unscoped.insert attributes_values
|