activerecord 3.1.12 → 3.2.0.rc1

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.

Files changed (99) hide show
  1. data/CHANGELOG.md +6263 -103
  2. data/README.rdoc +2 -2
  3. data/examples/performance.rb +55 -31
  4. data/lib/active_record.rb +28 -2
  5. data/lib/active_record/aggregations.rb +2 -2
  6. data/lib/active_record/associations.rb +82 -69
  7. data/lib/active_record/associations/association.rb +2 -37
  8. data/lib/active_record/associations/association_scope.rb +3 -30
  9. data/lib/active_record/associations/builder/association.rb +6 -4
  10. data/lib/active_record/associations/builder/belongs_to.rb +3 -3
  11. data/lib/active_record/associations/builder/collection_association.rb +2 -2
  12. data/lib/active_record/associations/builder/has_many.rb +4 -4
  13. data/lib/active_record/associations/builder/has_one.rb +5 -6
  14. data/lib/active_record/associations/builder/singular_association.rb +3 -16
  15. data/lib/active_record/associations/collection_association.rb +55 -28
  16. data/lib/active_record/associations/collection_proxy.rb +1 -35
  17. data/lib/active_record/associations/has_many_association.rb +5 -1
  18. data/lib/active_record/associations/has_many_through_association.rb +11 -8
  19. data/lib/active_record/associations/join_dependency.rb +1 -1
  20. data/lib/active_record/associations/preloader/association.rb +3 -1
  21. data/lib/active_record/attribute_assignment.rb +221 -0
  22. data/lib/active_record/attribute_methods.rb +212 -32
  23. data/lib/active_record/attribute_methods/deprecated_underscore_read.rb +32 -0
  24. data/lib/active_record/attribute_methods/dirty.rb +3 -3
  25. data/lib/active_record/attribute_methods/primary_key.rb +62 -25
  26. data/lib/active_record/attribute_methods/read.rb +69 -80
  27. data/lib/active_record/attribute_methods/serialization.rb +89 -0
  28. data/lib/active_record/attribute_methods/time_zone_conversion.rb +9 -14
  29. data/lib/active_record/attribute_methods/write.rb +27 -5
  30. data/lib/active_record/autosave_association.rb +23 -8
  31. data/lib/active_record/base.rb +223 -1712
  32. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +98 -132
  33. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +82 -29
  34. data/lib/active_record/connection_adapters/abstract/database_statements.rb +13 -42
  35. data/lib/active_record/connection_adapters/abstract/query_cache.rb +1 -1
  36. data/lib/active_record/connection_adapters/abstract/quoting.rb +7 -4
  37. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +36 -25
  38. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +41 -13
  39. data/lib/active_record/connection_adapters/abstract_adapter.rb +78 -43
  40. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +653 -0
  41. data/lib/active_record/connection_adapters/mysql2_adapter.rb +138 -578
  42. data/lib/active_record/connection_adapters/mysql_adapter.rb +86 -658
  43. data/lib/active_record/connection_adapters/postgresql_adapter.rb +144 -94
  44. data/lib/active_record/connection_adapters/schema_cache.rb +50 -0
  45. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +2 -6
  46. data/lib/active_record/connection_adapters/sqlite_adapter.rb +43 -22
  47. data/lib/active_record/counter_cache.rb +1 -1
  48. data/lib/active_record/dynamic_matchers.rb +79 -0
  49. data/lib/active_record/errors.rb +11 -1
  50. data/lib/active_record/explain.rb +83 -0
  51. data/lib/active_record/explain_subscriber.rb +21 -0
  52. data/lib/active_record/fixtures.rb +31 -76
  53. data/lib/active_record/fixtures/file.rb +65 -0
  54. data/lib/active_record/identity_map.rb +1 -7
  55. data/lib/active_record/inheritance.rb +167 -0
  56. data/lib/active_record/integration.rb +49 -0
  57. data/lib/active_record/locking/optimistic.rb +19 -11
  58. data/lib/active_record/locking/pessimistic.rb +1 -1
  59. data/lib/active_record/log_subscriber.rb +3 -3
  60. data/lib/active_record/migration.rb +38 -29
  61. data/lib/active_record/migration/command_recorder.rb +7 -7
  62. data/lib/active_record/model_schema.rb +362 -0
  63. data/lib/active_record/nested_attributes.rb +3 -2
  64. data/lib/active_record/persistence.rb +51 -1
  65. data/lib/active_record/querying.rb +58 -0
  66. data/lib/active_record/railtie.rb +24 -28
  67. data/lib/active_record/railties/controller_runtime.rb +3 -1
  68. data/lib/active_record/railties/databases.rake +133 -77
  69. data/lib/active_record/readonly_attributes.rb +26 -0
  70. data/lib/active_record/reflection.rb +7 -15
  71. data/lib/active_record/relation.rb +78 -35
  72. data/lib/active_record/relation/batches.rb +5 -2
  73. data/lib/active_record/relation/calculations.rb +27 -6
  74. data/lib/active_record/relation/delegation.rb +49 -0
  75. data/lib/active_record/relation/finder_methods.rb +5 -4
  76. data/lib/active_record/relation/predicate_builder.rb +13 -16
  77. data/lib/active_record/relation/query_methods.rb +59 -4
  78. data/lib/active_record/result.rb +1 -1
  79. data/lib/active_record/sanitization.rb +194 -0
  80. data/lib/active_record/schema_dumper.rb +5 -2
  81. data/lib/active_record/scoping.rb +152 -0
  82. data/lib/active_record/scoping/default.rb +140 -0
  83. data/lib/active_record/scoping/named.rb +202 -0
  84. data/lib/active_record/serialization.rb +1 -43
  85. data/lib/active_record/serializers/xml_serializer.rb +2 -44
  86. data/lib/active_record/session_store.rb +11 -11
  87. data/lib/active_record/store.rb +50 -0
  88. data/lib/active_record/test_case.rb +11 -7
  89. data/lib/active_record/timestamp.rb +16 -3
  90. data/lib/active_record/transactions.rb +5 -5
  91. data/lib/active_record/translation.rb +22 -0
  92. data/lib/active_record/validations.rb +1 -1
  93. data/lib/active_record/validations/associated.rb +5 -4
  94. data/lib/active_record/validations/uniqueness.rb +4 -4
  95. data/lib/active_record/version.rb +3 -3
  96. data/lib/rails/generators/active_record/session_migration/templates/migration.rb +1 -5
  97. metadata +48 -38
  98. checksums.yaml +0 -7
  99. data/lib/active_record/named_scope.rb +0 -200
@@ -1,12 +1,12 @@
1
1
  module ActiveRecord
2
2
  class Migration
3
- # ActiveRecord::Migration::CommandRecorder records commands done during
4
- # a migration and knows how to reverse those commands. The CommandRecorder
3
+ # <tt>ActiveRecord::Migration::CommandRecorder</tt> records commands done during
4
+ # a migration and knows how to reverse those commands. The CommandRecorder
5
5
  # knows how to invert the following commands:
6
6
  #
7
7
  # * add_column
8
8
  # * add_index
9
- # * add_timestamp
9
+ # * add_timestamps
10
10
  # * create_table
11
11
  # * remove_timestamps
12
12
  # * rename_column
@@ -20,21 +20,21 @@ module ActiveRecord
20
20
  @delegate = delegate
21
21
  end
22
22
 
23
- # record +command+. +command+ should be a method name and arguments.
23
+ # record +command+. +command+ should be a method name and arguments.
24
24
  # For example:
25
25
  #
26
- # recorder.record(:method_name, [:arg1, arg2])
26
+ # recorder.record(:method_name, [:arg1, :arg2])
27
27
  def record(*command)
28
28
  @commands << command
29
29
  end
30
30
 
31
31
  # Returns a list that represents commands that are the inverse of the
32
- # commands stored in +commands+. For example:
32
+ # commands stored in +commands+. For example:
33
33
  #
34
34
  # recorder.record(:rename_table, [:old, :new])
35
35
  # recorder.inverse # => [:rename_table, [:new, :old]]
36
36
  #
37
- # This method will raise an IrreversibleMigration exception if it cannot
37
+ # This method will raise an +IrreversibleMigration+ exception if it cannot
38
38
  # invert the +commands+.
39
39
  def inverse
40
40
  @commands.reverse.map { |name, args|
@@ -0,0 +1,362 @@
1
+ require 'active_support/concern'
2
+
3
+ module ActiveRecord
4
+ module ModelSchema
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ ##
9
+ # :singleton-method:
10
+ # Accessor for the prefix type that will be prepended to every primary key column name.
11
+ # The options are :table_name and :table_name_with_underscore. If the first is specified,
12
+ # the Product class will look for "productid" instead of "id" as the primary column. If the
13
+ # latter is specified, the Product class will look for "product_id" instead of "id". Remember
14
+ # that this is a global setting for all Active Records.
15
+ cattr_accessor :primary_key_prefix_type, :instance_writer => false
16
+ self.primary_key_prefix_type = nil
17
+
18
+ ##
19
+ # :singleton-method:
20
+ # Accessor for the name of the prefix string to prepend to every table name. So if set
21
+ # to "basecamp_", all table names will be named like "basecamp_projects", "basecamp_people",
22
+ # etc. This is a convenient way of creating a namespace for tables in a shared database.
23
+ # By default, the prefix is the empty string.
24
+ #
25
+ # If you are organising your models within modules you can add a prefix to the models within
26
+ # a namespace by defining a singleton method in the parent module called table_name_prefix which
27
+ # returns your chosen prefix.
28
+ class_attribute :table_name_prefix, :instance_writer => false
29
+ self.table_name_prefix = ""
30
+
31
+ ##
32
+ # :singleton-method:
33
+ # Works like +table_name_prefix+, but appends instead of prepends (set to "_basecamp" gives "projects_basecamp",
34
+ # "people_basecamp"). By default, the suffix is the empty string.
35
+ class_attribute :table_name_suffix, :instance_writer => false
36
+ self.table_name_suffix = ""
37
+
38
+ ##
39
+ # :singleton-method:
40
+ # Indicates whether table names should be the pluralized versions of the corresponding class names.
41
+ # If true, the default table name for a Product class will be +products+. If false, it would just be +product+.
42
+ # See table_name for the full rules on table/class naming. This is true, by default.
43
+ class_attribute :pluralize_table_names, :instance_writer => false
44
+ self.pluralize_table_names = true
45
+ end
46
+
47
+ module ClassMethods
48
+ # Guesses the table name (in forced lower-case) based on the name of the class in the
49
+ # inheritance hierarchy descending directly from ActiveRecord::Base. So if the hierarchy
50
+ # looks like: Reply < Message < ActiveRecord::Base, then Message is used
51
+ # to guess the table name even when called on Reply. The rules used to do the guess
52
+ # are handled by the Inflector class in Active Support, which knows almost all common
53
+ # English inflections. You can add new inflections in config/initializers/inflections.rb.
54
+ #
55
+ # Nested classes are given table names prefixed by the singular form of
56
+ # the parent's table name. Enclosing modules are not considered.
57
+ #
58
+ # ==== Examples
59
+ #
60
+ # class Invoice < ActiveRecord::Base
61
+ # end
62
+ #
63
+ # file class table_name
64
+ # invoice.rb Invoice invoices
65
+ #
66
+ # class Invoice < ActiveRecord::Base
67
+ # class Lineitem < ActiveRecord::Base
68
+ # end
69
+ # end
70
+ #
71
+ # file class table_name
72
+ # invoice.rb Invoice::Lineitem invoice_lineitems
73
+ #
74
+ # module Invoice
75
+ # class Lineitem < ActiveRecord::Base
76
+ # end
77
+ # end
78
+ #
79
+ # file class table_name
80
+ # invoice/lineitem.rb Invoice::Lineitem lineitems
81
+ #
82
+ # Additionally, the class-level +table_name_prefix+ is prepended and the
83
+ # +table_name_suffix+ is appended. So if you have "myapp_" as a prefix,
84
+ # the table name guess for an Invoice class becomes "myapp_invoices".
85
+ # Invoice::Lineitem becomes "myapp_invoice_lineitems".
86
+ #
87
+ # You can also set your own table name explicitly:
88
+ #
89
+ # class Mouse < ActiveRecord::Base
90
+ # self.table_name = "mice"
91
+ # end
92
+ #
93
+ # Alternatively, you can override the table_name method to define your
94
+ # own computation. (Possibly using <tt>super</tt> to manipulate the default
95
+ # table name.) Example:
96
+ #
97
+ # class Post < ActiveRecord::Base
98
+ # def self.table_name
99
+ # "special_" + super
100
+ # end
101
+ # end
102
+ # Post.table_name # => "special_posts"
103
+ def table_name
104
+ reset_table_name unless defined?(@table_name)
105
+ @table_name
106
+ end
107
+
108
+ def original_table_name #:nodoc:
109
+ deprecated_original_property_getter :table_name
110
+ end
111
+
112
+ # Sets the table name explicitly. Example:
113
+ #
114
+ # class Project < ActiveRecord::Base
115
+ # self.table_name = "project"
116
+ # end
117
+ #
118
+ # You can also just define your own <tt>self.table_name</tt> method; see
119
+ # the documentation for ActiveRecord::Base#table_name.
120
+ def table_name=(value)
121
+ @original_table_name = @table_name if defined?(@table_name)
122
+ @table_name = value
123
+ @quoted_table_name = nil
124
+ @arel_table = nil
125
+ @relation = Relation.new(self, arel_table)
126
+ end
127
+
128
+ def set_table_name(value = nil, &block) #:nodoc:
129
+ deprecated_property_setter :table_name, value, block
130
+ @quoted_table_name = nil
131
+ @arel_table = nil
132
+ @relation = Relation.new(self, arel_table)
133
+ end
134
+
135
+ # Returns a quoted version of the table name, used to construct SQL statements.
136
+ def quoted_table_name
137
+ @quoted_table_name ||= connection.quote_table_name(table_name)
138
+ end
139
+
140
+ # Computes the table name, (re)sets it internally, and returns it.
141
+ def reset_table_name #:nodoc:
142
+ if superclass.abstract_class?
143
+ self.table_name = superclass.table_name || compute_table_name
144
+ elsif abstract_class?
145
+ self.table_name = superclass == Base ? nil : superclass.table_name
146
+ else
147
+ self.table_name = compute_table_name
148
+ end
149
+ end
150
+
151
+ def full_table_name_prefix #:nodoc:
152
+ (parents.detect{ |p| p.respond_to?(:table_name_prefix) } || self).table_name_prefix
153
+ end
154
+
155
+ # The name of the column containing the object's class when Single Table Inheritance is used
156
+ def inheritance_column
157
+ if self == Base
158
+ 'type'
159
+ else
160
+ (@inheritance_column ||= nil) || superclass.inheritance_column
161
+ end
162
+ end
163
+
164
+ def original_inheritance_column #:nodoc:
165
+ deprecated_original_property_getter :inheritance_column
166
+ end
167
+
168
+ # Sets the value of inheritance_column
169
+ def inheritance_column=(value)
170
+ @original_inheritance_column = inheritance_column
171
+ @inheritance_column = value.to_s
172
+ end
173
+
174
+ def set_inheritance_column(value = nil, &block) #:nodoc:
175
+ deprecated_property_setter :inheritance_column, value, block
176
+ end
177
+
178
+ def sequence_name
179
+ if base_class == self
180
+ @sequence_name ||= reset_sequence_name
181
+ else
182
+ (@sequence_name ||= nil) || base_class.sequence_name
183
+ end
184
+ end
185
+
186
+ def original_sequence_name #:nodoc:
187
+ deprecated_original_property_getter :sequence_name
188
+ end
189
+
190
+ def reset_sequence_name #:nodoc:
191
+ self.sequence_name = connection.default_sequence_name(table_name, primary_key)
192
+ end
193
+
194
+ # Sets the name of the sequence to use when generating ids to the given
195
+ # value, or (if the value is nil or false) to the value returned by the
196
+ # given block. This is required for Oracle and is useful for any
197
+ # database which relies on sequences for primary key generation.
198
+ #
199
+ # If a sequence name is not explicitly set when using Oracle or Firebird,
200
+ # it will default to the commonly used pattern of: #{table_name}_seq
201
+ #
202
+ # If a sequence name is not explicitly set when using PostgreSQL, it
203
+ # will discover the sequence corresponding to your primary key for you.
204
+ #
205
+ # class Project < ActiveRecord::Base
206
+ # self.sequence_name = "projectseq" # default would have been "project_seq"
207
+ # end
208
+ def sequence_name=(value)
209
+ @original_sequence_name = @sequence_name if defined?(@sequence_name)
210
+ @sequence_name = value.to_s
211
+ end
212
+
213
+ def set_sequence_name(value = nil, &block) #:nodoc:
214
+ deprecated_property_setter :sequence_name, value, block
215
+ end
216
+
217
+ # Indicates whether the table associated with this class exists
218
+ def table_exists?
219
+ connection.schema_cache.table_exists?(table_name)
220
+ end
221
+
222
+ # Returns an array of column objects for the table associated with this class.
223
+ def columns
224
+ @columns ||= connection.schema_cache.columns[table_name].map do |col|
225
+ col = col.dup
226
+ col.primary = (col.name == primary_key)
227
+ col
228
+ end
229
+ end
230
+
231
+ # Returns a hash of column objects for the table associated with this class.
232
+ def columns_hash
233
+ @columns_hash ||= Hash[columns.map { |c| [c.name, c] }]
234
+ end
235
+
236
+ # Returns a hash where the keys are column names and the values are
237
+ # default values when instantiating the AR object for this table.
238
+ def column_defaults
239
+ @column_defaults ||= Hash[columns.map { |c| [c.name, c.default] }]
240
+ end
241
+
242
+ # Returns an array of column names as strings.
243
+ def column_names
244
+ @column_names ||= columns.map { |column| column.name }
245
+ end
246
+
247
+ # Returns an array of column objects where the primary id, all columns ending in "_id" or "_count",
248
+ # and columns used for single table inheritance have been removed.
249
+ def content_columns
250
+ @content_columns ||= columns.reject { |c| c.primary || c.name =~ /(_id|_count)$/ || c.name == inheritance_column }
251
+ end
252
+
253
+ # Returns a hash of all the methods added to query each of the columns in the table with the name of the method as the key
254
+ # and true as the value. This makes it possible to do O(1) lookups in respond_to? to check if a given method for attribute
255
+ # is available.
256
+ def column_methods_hash #:nodoc:
257
+ @dynamic_methods_hash ||= column_names.inject(Hash.new(false)) do |methods, attr|
258
+ attr_name = attr.to_s
259
+ methods[attr.to_sym] = attr_name
260
+ methods["#{attr}=".to_sym] = attr_name
261
+ methods["#{attr}?".to_sym] = attr_name
262
+ methods["#{attr}_before_type_cast".to_sym] = attr_name
263
+ methods
264
+ end
265
+ end
266
+
267
+ # Resets all the cached information about columns, which will cause them
268
+ # to be reloaded on the next request.
269
+ #
270
+ # The most common usage pattern for this method is probably in a migration,
271
+ # when just after creating a table you want to populate it with some default
272
+ # values, eg:
273
+ #
274
+ # class CreateJobLevels < ActiveRecord::Migration
275
+ # def up
276
+ # create_table :job_levels do |t|
277
+ # t.integer :id
278
+ # t.string :name
279
+ #
280
+ # t.timestamps
281
+ # end
282
+ #
283
+ # JobLevel.reset_column_information
284
+ # %w{assistant executive manager director}.each do |type|
285
+ # JobLevel.create(:name => type)
286
+ # end
287
+ # end
288
+ #
289
+ # def down
290
+ # drop_table :job_levels
291
+ # end
292
+ # end
293
+ def reset_column_information
294
+ connection.clear_cache!
295
+ undefine_attribute_methods
296
+ connection.schema_cache.clear_table_cache!(table_name) if table_exists?
297
+
298
+ @column_names = @content_columns = @column_defaults = @columns = @columns_hash = nil
299
+ @dynamic_methods_hash = @inheritance_column = nil
300
+ @arel_engine = @relation = nil
301
+ end
302
+
303
+ def clear_cache! # :nodoc:
304
+ connection.schema_cache.clear!
305
+ end
306
+
307
+ private
308
+
309
+ # Guesses the table name, but does not decorate it with prefix and suffix information.
310
+ def undecorated_table_name(class_name = base_class.name)
311
+ table_name = class_name.to_s.demodulize.underscore
312
+ table_name = table_name.pluralize if pluralize_table_names
313
+ table_name
314
+ end
315
+
316
+ # Computes and returns a table name according to default conventions.
317
+ def compute_table_name
318
+ base = base_class
319
+ if self == base
320
+ # Nested classes are prefixed with singular parent table name.
321
+ if parent < ActiveRecord::Base && !parent.abstract_class?
322
+ contained = parent.table_name
323
+ contained = contained.singularize if parent.pluralize_table_names
324
+ contained += '_'
325
+ end
326
+ "#{full_table_name_prefix}#{contained}#{undecorated_table_name(name)}#{table_name_suffix}"
327
+ else
328
+ # STI subclasses always use their superclass' table.
329
+ base.table_name
330
+ end
331
+ end
332
+
333
+ def deprecated_property_setter(property, value, block)
334
+ if block
335
+ ActiveSupport::Deprecation.warn(
336
+ "Calling set_#{property} is deprecated. If you need to lazily evaluate " \
337
+ "the #{property}, define your own `self.#{property}` class method. You can use `super` " \
338
+ "to get the default #{property} where you would have called `original_#{property}`."
339
+ )
340
+
341
+ define_attr_method property, value, false, &block
342
+ else
343
+ ActiveSupport::Deprecation.warn(
344
+ "Calling set_#{property} is deprecated. Please use `self.#{property} = 'the_name'` instead."
345
+ )
346
+
347
+ define_attr_method property, value, false
348
+ end
349
+ end
350
+
351
+ def deprecated_original_property_getter(property)
352
+ ActiveSupport::Deprecation.warn("original_#{property} is deprecated. Define self.#{property} and call super instead.")
353
+
354
+ if !instance_variable_defined?("@original_#{property}") && respond_to?("reset_#{property}")
355
+ send("reset_#{property}")
356
+ else
357
+ instance_variable_get("@original_#{property}")
358
+ end
359
+ end
360
+ end
361
+ end
362
+ end
@@ -220,7 +220,7 @@ module ActiveRecord
220
220
  # validates_presence_of :member
221
221
  # end
222
222
  module ClassMethods
223
- REJECT_ALL_BLANK_PROC = proc { |attributes| attributes.all? { |_, value| value.blank? } }
223
+ REJECT_ALL_BLANK_PROC = proc { |attributes| attributes.all? { |key, value| key == '_destroy' || value.blank? } }
224
224
 
225
225
  # Defines an attributes writer for the specified association(s). If you
226
226
  # are using <tt>attr_protected</tt> or <tt>attr_accessible</tt>, then you
@@ -239,7 +239,8 @@ module ActiveRecord
239
239
  # is specified, a record will be built for all attribute hashes that
240
240
  # do not have a <tt>_destroy</tt> value that evaluates to true.
241
241
  # Passing <tt>:all_blank</tt> instead of a Proc will create a proc
242
- # that will reject a record where all the attributes are blank.
242
+ # that will reject a record where all the attributes are blank excluding
243
+ # any value for _destroy.
243
244
  # [:limit]
244
245
  # Allows you to specify the maximum number of the associated records that
245
246
  # can be processed with the nested attributes. If the size of the
@@ -1,6 +1,53 @@
1
+ require 'active_support/concern'
2
+
1
3
  module ActiveRecord
2
4
  # = Active Record Persistence
3
5
  module Persistence
6
+ extend ActiveSupport::Concern
7
+
8
+ module ClassMethods
9
+ # Creates an object (or multiple objects) and saves it to the database, if validations pass.
10
+ # The resulting object is returned whether the object was saved successfully to the database or not.
11
+ #
12
+ # The +attributes+ parameter can be either be a Hash or an Array of Hashes. These Hashes describe the
13
+ # attributes on the objects that are to be created.
14
+ #
15
+ # +create+ respects mass-assignment security and accepts either +:as+ or +:without_protection+ options
16
+ # in the +options+ parameter.
17
+ #
18
+ # ==== Examples
19
+ # # Create a single new object
20
+ # User.create(:first_name => 'Jamie')
21
+ #
22
+ # # Create a single new object using the :admin mass-assignment security role
23
+ # User.create({ :first_name => 'Jamie', :is_admin => true }, :as => :admin)
24
+ #
25
+ # # Create a single new object bypassing mass-assignment security
26
+ # User.create({ :first_name => 'Jamie', :is_admin => true }, :without_protection => true)
27
+ #
28
+ # # Create an Array of new objects
29
+ # User.create([{ :first_name => 'Jamie' }, { :first_name => 'Jeremy' }])
30
+ #
31
+ # # Create a single object and pass it into a block to set other attributes.
32
+ # User.create(:first_name => 'Jamie') do |u|
33
+ # u.is_admin = false
34
+ # end
35
+ #
36
+ # # Creating an Array of new objects using a block, where the block is executed for each object:
37
+ # User.create([{ :first_name => 'Jamie' }, { :first_name => 'Jeremy' }]) do |u|
38
+ # u.is_admin = false
39
+ # end
40
+ def create(attributes = nil, options = {}, &block)
41
+ if attributes.is_a?(Array)
42
+ attributes.collect { |attr| create(attr, options, &block) }
43
+ else
44
+ object = new(attributes, options, &block)
45
+ object.save
46
+ object
47
+ end
48
+ end
49
+ end
50
+
4
51
  # Returns true if this object hasn't been saved yet -- that is, a record
5
52
  # for the object doesn't exist in the data store yet; otherwise, returns false.
6
53
  def new_record?
@@ -114,6 +161,7 @@ module ActiveRecord
114
161
  became.instance_variable_set("@attributes_cache", @attributes_cache)
115
162
  became.instance_variable_set("@new_record", new_record?)
116
163
  became.instance_variable_set("@destroyed", destroyed?)
164
+ became.instance_variable_set("@errors", errors)
117
165
  became.type = klass.name unless self.class.descends_from_active_record?
118
166
  became
119
167
  end
@@ -139,6 +187,8 @@ module ActiveRecord
139
187
  # * Callbacks are skipped.
140
188
  # * updated_at/updated_on column is not updated if that column is available.
141
189
  #
190
+ # Raises an +ActiveRecordError+ when called on new objects, or when the +name+
191
+ # attribute is marked as readonly.
142
192
  def update_column(name, value)
143
193
  name = name.to_s
144
194
  raise ActiveRecordError, "#{name} is marked as readonly" if self.class.readonly_attributes.include?(name)
@@ -312,7 +362,7 @@ module ActiveRecord
312
362
 
313
363
  new_id = self.class.unscoped.insert attributes_values
314
364
 
315
- self.id ||= new_id
365
+ self.id ||= new_id if self.class.primary_key
316
366
 
317
367
  IdentityMap.add(self) if IdentityMap.enabled?
318
368
  @new_record = false