activerecord 3.1.11 → 3.2.0

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.
Files changed (106) hide show
  1. data/CHANGELOG.md +6294 -97
  2. data/README.rdoc +2 -2
  3. data/examples/performance.rb +55 -31
  4. data/lib/active_record/aggregations.rb +2 -2
  5. data/lib/active_record/associations/association.rb +2 -42
  6. data/lib/active_record/associations/association_scope.rb +3 -30
  7. data/lib/active_record/associations/builder/association.rb +6 -4
  8. data/lib/active_record/associations/builder/belongs_to.rb +3 -3
  9. data/lib/active_record/associations/builder/collection_association.rb +2 -2
  10. data/lib/active_record/associations/builder/has_many.rb +4 -4
  11. data/lib/active_record/associations/builder/has_one.rb +5 -6
  12. data/lib/active_record/associations/builder/singular_association.rb +3 -16
  13. data/lib/active_record/associations/collection_association.rb +55 -28
  14. data/lib/active_record/associations/collection_proxy.rb +1 -35
  15. data/lib/active_record/associations/has_many_association.rb +5 -1
  16. data/lib/active_record/associations/has_many_through_association.rb +11 -8
  17. data/lib/active_record/associations/join_dependency.rb +1 -1
  18. data/lib/active_record/associations/preloader/association.rb +3 -1
  19. data/lib/active_record/associations.rb +82 -69
  20. data/lib/active_record/attribute_assignment.rb +221 -0
  21. data/lib/active_record/attribute_methods/deprecated_underscore_read.rb +32 -0
  22. data/lib/active_record/attribute_methods/dirty.rb +3 -3
  23. data/lib/active_record/attribute_methods/primary_key.rb +62 -25
  24. data/lib/active_record/attribute_methods/read.rb +72 -83
  25. data/lib/active_record/attribute_methods/serialization.rb +93 -0
  26. data/lib/active_record/attribute_methods/time_zone_conversion.rb +9 -14
  27. data/lib/active_record/attribute_methods/write.rb +27 -5
  28. data/lib/active_record/attribute_methods.rb +209 -30
  29. data/lib/active_record/autosave_association.rb +23 -8
  30. data/lib/active_record/base.rb +217 -1709
  31. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +98 -132
  32. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +82 -29
  33. data/lib/active_record/connection_adapters/abstract/database_statements.rb +13 -42
  34. data/lib/active_record/connection_adapters/abstract/query_cache.rb +1 -1
  35. data/lib/active_record/connection_adapters/abstract/quoting.rb +9 -12
  36. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +36 -25
  37. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +43 -22
  38. data/lib/active_record/connection_adapters/abstract_adapter.rb +78 -43
  39. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +653 -0
  40. data/lib/active_record/connection_adapters/column.rb +2 -2
  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 +4 -3
  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/file.rb +65 -0
  53. data/lib/active_record/fixtures.rb +31 -76
  54. data/lib/active_record/identity_map.rb +4 -11
  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 +30 -25
  58. data/lib/active_record/locking/pessimistic.rb +23 -1
  59. data/lib/active_record/log_subscriber.rb +3 -3
  60. data/lib/active_record/migration/command_recorder.rb +8 -8
  61. data/lib/active_record/migration.rb +47 -30
  62. data/lib/active_record/model_schema.rb +366 -0
  63. data/lib/active_record/nested_attributes.rb +3 -2
  64. data/lib/active_record/persistence.rb +51 -9
  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 +134 -77
  69. data/lib/active_record/railties/jdbcmysql_error.rb +1 -1
  70. data/lib/active_record/readonly_attributes.rb +26 -0
  71. data/lib/active_record/reflection.rb +7 -15
  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 +6 -5
  76. data/lib/active_record/relation/predicate_builder.rb +12 -19
  77. data/lib/active_record/relation/query_methods.rb +76 -10
  78. data/lib/active_record/relation/spawn_methods.rb +11 -2
  79. data/lib/active_record/relation.rb +77 -34
  80. data/lib/active_record/result.rb +1 -1
  81. data/lib/active_record/sanitization.rb +194 -0
  82. data/lib/active_record/schema_dumper.rb +5 -2
  83. data/lib/active_record/scoping/default.rb +142 -0
  84. data/lib/active_record/scoping/named.rb +202 -0
  85. data/lib/active_record/scoping.rb +152 -0
  86. data/lib/active_record/serialization.rb +1 -43
  87. data/lib/active_record/serializers/xml_serializer.rb +2 -44
  88. data/lib/active_record/session_store.rb +15 -15
  89. data/lib/active_record/store.rb +50 -0
  90. data/lib/active_record/test_case.rb +11 -7
  91. data/lib/active_record/timestamp.rb +16 -3
  92. data/lib/active_record/transactions.rb +5 -5
  93. data/lib/active_record/translation.rb +22 -0
  94. data/lib/active_record/validations/associated.rb +5 -4
  95. data/lib/active_record/validations/uniqueness.rb +4 -4
  96. data/lib/active_record/validations.rb +1 -1
  97. data/lib/active_record/version.rb +2 -2
  98. data/lib/active_record.rb +28 -2
  99. data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -1
  100. data/lib/rails/generators/active_record/migration/templates/migration.rb +9 -3
  101. data/lib/rails/generators/active_record/model/model_generator.rb +5 -1
  102. data/lib/rails/generators/active_record/model/templates/migration.rb +3 -5
  103. data/lib/rails/generators/active_record/session_migration/templates/migration.rb +1 -5
  104. metadata +50 -40
  105. checksums.yaml +0 -7
  106. data/lib/active_record/named_scope.rb +0 -200
@@ -0,0 +1,366 @@
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 abstract_class?
143
+ self.table_name = if superclass == Base || superclass.abstract_class?
144
+ nil
145
+ else
146
+ superclass.table_name
147
+ end
148
+ elsif superclass.abstract_class?
149
+ self.table_name = superclass.table_name || compute_table_name
150
+ else
151
+ self.table_name = compute_table_name
152
+ end
153
+ end
154
+
155
+ def full_table_name_prefix #:nodoc:
156
+ (parents.detect{ |p| p.respond_to?(:table_name_prefix) } || self).table_name_prefix
157
+ end
158
+
159
+ # The name of the column containing the object's class when Single Table Inheritance is used
160
+ def inheritance_column
161
+ if self == Base
162
+ 'type'
163
+ else
164
+ (@inheritance_column ||= nil) || superclass.inheritance_column
165
+ end
166
+ end
167
+
168
+ def original_inheritance_column #:nodoc:
169
+ deprecated_original_property_getter :inheritance_column
170
+ end
171
+
172
+ # Sets the value of inheritance_column
173
+ def inheritance_column=(value)
174
+ @original_inheritance_column = inheritance_column
175
+ @inheritance_column = value.to_s
176
+ end
177
+
178
+ def set_inheritance_column(value = nil, &block) #:nodoc:
179
+ deprecated_property_setter :inheritance_column, value, block
180
+ end
181
+
182
+ def sequence_name
183
+ if base_class == self
184
+ @sequence_name ||= reset_sequence_name
185
+ else
186
+ (@sequence_name ||= nil) || base_class.sequence_name
187
+ end
188
+ end
189
+
190
+ def original_sequence_name #:nodoc:
191
+ deprecated_original_property_getter :sequence_name
192
+ end
193
+
194
+ def reset_sequence_name #:nodoc:
195
+ self.sequence_name = connection.default_sequence_name(table_name, primary_key)
196
+ end
197
+
198
+ # Sets the name of the sequence to use when generating ids to the given
199
+ # value, or (if the value is nil or false) to the value returned by the
200
+ # given block. This is required for Oracle and is useful for any
201
+ # database which relies on sequences for primary key generation.
202
+ #
203
+ # If a sequence name is not explicitly set when using Oracle or Firebird,
204
+ # it will default to the commonly used pattern of: #{table_name}_seq
205
+ #
206
+ # If a sequence name is not explicitly set when using PostgreSQL, it
207
+ # will discover the sequence corresponding to your primary key for you.
208
+ #
209
+ # class Project < ActiveRecord::Base
210
+ # self.sequence_name = "projectseq" # default would have been "project_seq"
211
+ # end
212
+ def sequence_name=(value)
213
+ @original_sequence_name = @sequence_name if defined?(@sequence_name)
214
+ @sequence_name = value.to_s
215
+ end
216
+
217
+ def set_sequence_name(value = nil, &block) #:nodoc:
218
+ deprecated_property_setter :sequence_name, value, block
219
+ end
220
+
221
+ # Indicates whether the table associated with this class exists
222
+ def table_exists?
223
+ connection.schema_cache.table_exists?(table_name)
224
+ end
225
+
226
+ # Returns an array of column objects for the table associated with this class.
227
+ def columns
228
+ @columns ||= connection.schema_cache.columns[table_name].map do |col|
229
+ col = col.dup
230
+ col.primary = (col.name == primary_key)
231
+ col
232
+ end
233
+ end
234
+
235
+ # Returns a hash of column objects for the table associated with this class.
236
+ def columns_hash
237
+ @columns_hash ||= Hash[columns.map { |c| [c.name, c] }]
238
+ end
239
+
240
+ # Returns a hash where the keys are column names and the values are
241
+ # default values when instantiating the AR object for this table.
242
+ def column_defaults
243
+ @column_defaults ||= Hash[columns.map { |c| [c.name, c.default] }]
244
+ end
245
+
246
+ # Returns an array of column names as strings.
247
+ def column_names
248
+ @column_names ||= columns.map { |column| column.name }
249
+ end
250
+
251
+ # Returns an array of column objects where the primary id, all columns ending in "_id" or "_count",
252
+ # and columns used for single table inheritance have been removed.
253
+ def content_columns
254
+ @content_columns ||= columns.reject { |c| c.primary || c.name =~ /(_id|_count)$/ || c.name == inheritance_column }
255
+ end
256
+
257
+ # 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
258
+ # 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
259
+ # is available.
260
+ def column_methods_hash #:nodoc:
261
+ @dynamic_methods_hash ||= column_names.inject(Hash.new(false)) do |methods, attr|
262
+ attr_name = attr.to_s
263
+ methods[attr.to_sym] = attr_name
264
+ methods["#{attr}=".to_sym] = attr_name
265
+ methods["#{attr}?".to_sym] = attr_name
266
+ methods["#{attr}_before_type_cast".to_sym] = attr_name
267
+ methods
268
+ end
269
+ end
270
+
271
+ # Resets all the cached information about columns, which will cause them
272
+ # to be reloaded on the next request.
273
+ #
274
+ # The most common usage pattern for this method is probably in a migration,
275
+ # when just after creating a table you want to populate it with some default
276
+ # values, eg:
277
+ #
278
+ # class CreateJobLevels < ActiveRecord::Migration
279
+ # def up
280
+ # create_table :job_levels do |t|
281
+ # t.integer :id
282
+ # t.string :name
283
+ #
284
+ # t.timestamps
285
+ # end
286
+ #
287
+ # JobLevel.reset_column_information
288
+ # %w{assistant executive manager director}.each do |type|
289
+ # JobLevel.create(:name => type)
290
+ # end
291
+ # end
292
+ #
293
+ # def down
294
+ # drop_table :job_levels
295
+ # end
296
+ # end
297
+ def reset_column_information
298
+ connection.clear_cache!
299
+ undefine_attribute_methods
300
+ connection.schema_cache.clear_table_cache!(table_name) if table_exists?
301
+
302
+ @column_names = @content_columns = @column_defaults = @columns = @columns_hash = nil
303
+ @dynamic_methods_hash = @inheritance_column = nil
304
+ @arel_engine = @relation = nil
305
+ end
306
+
307
+ def clear_cache! # :nodoc:
308
+ connection.schema_cache.clear!
309
+ end
310
+
311
+ private
312
+
313
+ # Guesses the table name, but does not decorate it with prefix and suffix information.
314
+ def undecorated_table_name(class_name = base_class.name)
315
+ table_name = class_name.to_s.demodulize.underscore
316
+ table_name = table_name.pluralize if pluralize_table_names
317
+ table_name
318
+ end
319
+
320
+ # Computes and returns a table name according to default conventions.
321
+ def compute_table_name
322
+ base = base_class
323
+ if self == base
324
+ # Nested classes are prefixed with singular parent table name.
325
+ if parent < ActiveRecord::Base && !parent.abstract_class?
326
+ contained = parent.table_name
327
+ contained = contained.singularize if parent.pluralize_table_names
328
+ contained += '_'
329
+ end
330
+ "#{full_table_name_prefix}#{contained}#{undecorated_table_name(name)}#{table_name_suffix}"
331
+ else
332
+ # STI subclasses always use their superclass' table.
333
+ base.table_name
334
+ end
335
+ end
336
+
337
+ def deprecated_property_setter(property, value, block)
338
+ if block
339
+ ActiveSupport::Deprecation.warn(
340
+ "Calling set_#{property} is deprecated. If you need to lazily evaluate " \
341
+ "the #{property}, define your own `self.#{property}` class method. You can use `super` " \
342
+ "to get the default #{property} where you would have called `original_#{property}`."
343
+ )
344
+
345
+ define_attr_method property, value, false, &block
346
+ else
347
+ ActiveSupport::Deprecation.warn(
348
+ "Calling set_#{property} is deprecated. Please use `self.#{property} = 'the_name'` instead."
349
+ )
350
+
351
+ define_attr_method property, value, false
352
+ end
353
+ end
354
+
355
+ def deprecated_original_property_getter(property)
356
+ ActiveSupport::Deprecation.warn("original_#{property} is deprecated. Define self.#{property} and call super instead.")
357
+
358
+ if !instance_variable_defined?("@original_#{property}") && respond_to?("reset_#{property}")
359
+ send("reset_#{property}")
360
+ else
361
+ instance_variable_get("@original_#{property}")
362
+ end
363
+ end
364
+ end
365
+ end
366
+ 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,19 +362,11 @@ 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
319
369
  id
320
370
  end
321
-
322
- # Initializes the attributes array with keys matching the columns from the linked table and
323
- # the values matching the corresponding default value of that column, so
324
- # that a new instance, or one populated from a passed-in Hash, still has all the attributes
325
- # that instances loaded from the database would.
326
- def attributes_from_column_definition
327
- self.class.column_defaults.dup
328
- end
329
371
  end
330
372
  end
@@ -0,0 +1,58 @@
1
+ require 'active_support/core_ext/module/delegation'
2
+
3
+ module ActiveRecord
4
+ module Querying
5
+ delegate :find, :first, :first!, :last, :last!, :all, :exists?, :any?, :many?, :to => :scoped
6
+ delegate :first_or_create, :first_or_create!, :first_or_initialize, :to => :scoped
7
+ delegate :destroy, :destroy_all, :delete, :delete_all, :update, :update_all, :to => :scoped
8
+ delegate :find_each, :find_in_batches, :to => :scoped
9
+ delegate :select, :group, :order, :except, :reorder, :limit, :offset, :joins,
10
+ :where, :preload, :eager_load, :includes, :from, :lock, :readonly,
11
+ :having, :create_with, :uniq, :to => :scoped
12
+ delegate :count, :average, :minimum, :maximum, :sum, :calculate, :pluck, :to => :scoped
13
+
14
+ # Executes a custom SQL query against your database and returns all the results. The results will
15
+ # be returned as an array with columns requested encapsulated as attributes of the model you call
16
+ # this method from. If you call <tt>Product.find_by_sql</tt> then the results will be returned in
17
+ # a Product object with the attributes you specified in the SQL query.
18
+ #
19
+ # If you call a complicated SQL query which spans multiple tables the columns specified by the
20
+ # SELECT will be attributes of the model, whether or not they are columns of the corresponding
21
+ # table.
22
+ #
23
+ # The +sql+ parameter is a full SQL query as a string. It will be called as is, there will be
24
+ # no database agnostic conversions performed. This should be a last resort because using, for example,
25
+ # MySQL specific terms will lock you to using that particular database engine or require you to
26
+ # change your call if you switch engines.
27
+ #
28
+ # ==== Examples
29
+ # # A simple SQL query spanning multiple tables
30
+ # Post.find_by_sql "SELECT p.title, c.author FROM posts p, comments c WHERE p.id = c.post_id"
31
+ # > [#<Post:0x36bff9c @attributes={"title"=>"Ruby Meetup", "first_name"=>"Quentin"}>, ...]
32
+ #
33
+ # # You can use the same string replacement techniques as you can with ActiveRecord#find
34
+ # Post.find_by_sql ["SELECT title FROM posts WHERE author = ? AND created > ?", author_id, start_date]
35
+ # > [#<Post:0x36bff9c @attributes={"title"=>"The Cheap Man Buys Twice"}>, ...]
36
+ def find_by_sql(sql, binds = [])
37
+ logging_query_plan do
38
+ connection.select_all(sanitize_sql(sql), "#{name} Load", binds).collect! { |record| instantiate(record) }
39
+ end
40
+ end
41
+
42
+ # Returns the result of an SQL statement that should only include a COUNT(*) in the SELECT part.
43
+ # The use of this method should be restricted to complicated SQL queries that can't be executed
44
+ # using the ActiveRecord::Calculations class methods. Look into those before using this.
45
+ #
46
+ # ==== Parameters
47
+ #
48
+ # * +sql+ - An SQL statement which should return a count query from the database, see the example below.
49
+ #
50
+ # ==== Examples
51
+ #
52
+ # Product.count_by_sql "SELECT COUNT(*) FROM sales s, customers c WHERE s.customer_id = c.id"
53
+ def count_by_sql(sql)
54
+ sql = sanitize_conditions(sql)
55
+ connection.select_value(sql, "#{name} Count").to_i
56
+ end
57
+ end
58
+ end
@@ -22,6 +22,13 @@ module ActiveRecord
22
22
  config.app_middleware.insert_after "::ActionDispatch::Callbacks",
23
23
  "ActiveRecord::ConnectionAdapters::ConnectionManagement"
24
24
 
25
+ config.action_dispatch.rescue_responses.merge!(
26
+ 'ActiveRecord::RecordNotFound' => :not_found,
27
+ 'ActiveRecord::StaleObjectError' => :conflict,
28
+ 'ActiveRecord::RecordInvalid' => :unprocessable_entity,
29
+ 'ActiveRecord::RecordNotSaved' => :unprocessable_entity
30
+ )
31
+
25
32
  rake_tasks do
26
33
  load "active_record/railties/databases.rake"
27
34
  end
@@ -78,15 +85,27 @@ module ActiveRecord
78
85
  end
79
86
  end
80
87
 
81
- initializer "active_record.set_dispatch_hooks", :before => :set_clear_dependencies_hook do |app|
82
- ActiveSupport.on_load(:active_record) do
83
- ActionDispatch::Reloader.to_cleanup do
84
- ActiveRecord::Base.clear_reloadable_connections!
85
- ActiveRecord::Base.clear_cache!
88
+ initializer "active_record.set_reloader_hooks" do |app|
89
+ hook = lambda do
90
+ ActiveRecord::Base.clear_reloadable_connections!
91
+ ActiveRecord::Base.clear_cache!
92
+ end
93
+
94
+ if app.config.reload_classes_only_on_change
95
+ ActiveSupport.on_load(:active_record) do
96
+ ActionDispatch::Reloader.to_prepare(&hook)
97
+ end
98
+ else
99
+ ActiveSupport.on_load(:active_record) do
100
+ ActionDispatch::Reloader.to_cleanup(&hook)
86
101
  end
87
102
  end
88
103
  end
89
104
 
105
+ initializer "active_record.add_watchable_files" do |app|
106
+ config.watchable_files.concat ["#{app.root}/db/schema.rb", "#{app.root}/db/structure.sql"]
107
+ end
108
+
90
109
  config.after_initialize do
91
110
  ActiveSupport.on_load(:active_record) do
92
111
  instantiate_observers
@@ -96,28 +115,5 @@ module ActiveRecord
96
115
  end
97
116
  end
98
117
  end
99
-
100
- config.after_initialize do
101
- container = :"activerecord.attributes"
102
- lookup = I18n.t(container, :default => {})
103
- if lookup.is_a?(Hash)
104
- lookup.each do |key, value|
105
- if value.is_a?(Hash) && value.any? { |k,v| v.is_a?(Hash) }
106
- $stderr.puts "[DEPRECATION WARNING] Nested I18n namespace lookup under \"#{container}.#{key}\" is no longer supported"
107
- end
108
- end
109
- end
110
-
111
- container = :"activerecord.models"
112
- lookup = I18n.t(container, :default => {})
113
- if lookup.is_a?(Hash)
114
- lookup.each do |key, value|
115
- if value.is_a?(Hash) && !value.key?(:one)
116
- $stderr.puts "[DEPRECATION WARNING] Nested I18n namespace lookup under \"#{container}.#{key}\" is no longer supported"
117
- end
118
- end
119
- end
120
- end
121
-
122
118
  end
123
119
  end
@@ -32,7 +32,9 @@ module ActiveRecord
32
32
 
33
33
  def append_info_to_payload(payload)
34
34
  super
35
- payload[:db_runtime] = db_runtime
35
+ if ActiveRecord::Base.connected?
36
+ payload[:db_runtime] = (db_runtime || 0) + ActiveRecord::LogSubscriber.reset_runtime
37
+ end
36
38
  end
37
39
 
38
40
  module ClassMethods