activerecord 3.1.9 → 3.2.12
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.
- checksums.yaml +6 -6
- data/CHANGELOG.md +317 -336
- data/README.rdoc +3 -3
- data/examples/performance.rb +20 -1
- data/lib/active_record/aggregations.rb +1 -1
- data/lib/active_record/associations/alias_tracker.rb +3 -6
- data/lib/active_record/associations/association.rb +3 -42
- data/lib/active_record/associations/association_scope.rb +3 -15
- data/lib/active_record/associations/builder/association.rb +6 -4
- data/lib/active_record/associations/builder/belongs_to.rb +3 -3
- data/lib/active_record/associations/builder/collection_association.rb +2 -2
- data/lib/active_record/associations/builder/has_many.rb +4 -4
- data/lib/active_record/associations/builder/has_one.rb +5 -6
- data/lib/active_record/associations/builder/singular_association.rb +3 -16
- data/lib/active_record/associations/collection_association.rb +64 -31
- data/lib/active_record/associations/collection_proxy.rb +2 -37
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +1 -0
- data/lib/active_record/associations/has_many_association.rb +5 -1
- data/lib/active_record/associations/has_many_through_association.rb +28 -9
- data/lib/active_record/associations/has_one_association.rb +15 -13
- data/lib/active_record/associations/join_dependency.rb +2 -2
- data/lib/active_record/associations/preloader.rb +14 -10
- data/lib/active_record/associations/through_association.rb +7 -3
- data/lib/active_record/associations.rb +92 -76
- data/lib/active_record/attribute_assignment.rb +221 -0
- data/lib/active_record/attribute_methods/deprecated_underscore_read.rb +32 -0
- data/lib/active_record/attribute_methods/dirty.rb +21 -11
- data/lib/active_record/attribute_methods/primary_key.rb +62 -25
- data/lib/active_record/attribute_methods/read.rb +73 -83
- data/lib/active_record/attribute_methods/serialization.rb +102 -0
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +23 -17
- data/lib/active_record/attribute_methods/write.rb +31 -6
- data/lib/active_record/attribute_methods.rb +231 -30
- data/lib/active_record/autosave_association.rb +43 -22
- data/lib/active_record/base.rb +227 -1708
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +150 -148
- data/lib/active_record/connection_adapters/abstract/connection_specification.rb +85 -29
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +6 -33
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +10 -2
- data/lib/active_record/connection_adapters/abstract/quoting.rb +15 -6
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +37 -26
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +48 -19
- data/lib/active_record/connection_adapters/abstract_adapter.rb +77 -42
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +674 -0
- data/lib/active_record/connection_adapters/column.rb +37 -11
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +129 -581
- data/lib/active_record/connection_adapters/mysql_adapter.rb +137 -696
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +184 -86
- data/lib/active_record/connection_adapters/schema_cache.rb +50 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +2 -6
- data/lib/active_record/connection_adapters/sqlite_adapter.rb +55 -32
- data/lib/active_record/counter_cache.rb +9 -4
- data/lib/active_record/dynamic_finder_match.rb +12 -0
- data/lib/active_record/dynamic_matchers.rb +84 -0
- data/lib/active_record/errors.rb +11 -1
- data/lib/active_record/explain.rb +85 -0
- data/lib/active_record/explain_subscriber.rb +25 -0
- data/lib/active_record/fixtures/file.rb +65 -0
- data/lib/active_record/fixtures.rb +56 -85
- data/lib/active_record/identity_map.rb +3 -4
- data/lib/active_record/inheritance.rb +174 -0
- data/lib/active_record/integration.rb +49 -0
- data/lib/active_record/locking/optimistic.rb +30 -25
- data/lib/active_record/locking/pessimistic.rb +23 -1
- data/lib/active_record/log_subscriber.rb +3 -3
- data/lib/active_record/migration/command_recorder.rb +8 -8
- data/lib/active_record/migration.rb +68 -35
- data/lib/active_record/model_schema.rb +366 -0
- data/lib/active_record/nested_attributes.rb +3 -2
- data/lib/active_record/persistence.rb +57 -11
- data/lib/active_record/querying.rb +58 -0
- data/lib/active_record/railtie.rb +31 -29
- data/lib/active_record/railties/controller_runtime.rb +3 -1
- data/lib/active_record/railties/databases.rake +191 -110
- data/lib/active_record/railties/jdbcmysql_error.rb +1 -1
- data/lib/active_record/readonly_attributes.rb +26 -0
- data/lib/active_record/reflection.rb +7 -15
- data/lib/active_record/relation/batches.rb +5 -2
- data/lib/active_record/relation/calculations.rb +47 -15
- data/lib/active_record/relation/delegation.rb +49 -0
- data/lib/active_record/relation/finder_methods.rb +9 -7
- data/lib/active_record/relation/predicate_builder.rb +18 -7
- data/lib/active_record/relation/query_methods.rb +75 -9
- data/lib/active_record/relation/spawn_methods.rb +11 -2
- data/lib/active_record/relation.rb +78 -32
- data/lib/active_record/result.rb +1 -1
- data/lib/active_record/sanitization.rb +194 -0
- data/lib/active_record/schema_dumper.rb +12 -5
- data/lib/active_record/scoping/default.rb +142 -0
- data/lib/active_record/scoping/named.rb +202 -0
- data/lib/active_record/scoping.rb +152 -0
- data/lib/active_record/serialization.rb +1 -43
- data/lib/active_record/serializers/xml_serializer.rb +4 -45
- data/lib/active_record/session_store.rb +17 -15
- data/lib/active_record/store.rb +52 -0
- data/lib/active_record/test_case.rb +11 -7
- data/lib/active_record/timestamp.rb +17 -3
- data/lib/active_record/transactions.rb +27 -6
- data/lib/active_record/translation.rb +22 -0
- data/lib/active_record/validations/associated.rb +5 -4
- data/lib/active_record/validations/uniqueness.rb +7 -7
- data/lib/active_record/validations.rb +1 -1
- data/lib/active_record/version.rb +2 -2
- data/lib/active_record.rb +38 -3
- data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -1
- data/lib/rails/generators/active_record/migration/templates/migration.rb +12 -3
- data/lib/rails/generators/active_record/model/model_generator.rb +9 -1
- data/lib/rails/generators/active_record/model/templates/migration.rb +3 -5
- data/lib/rails/generators/active_record/model/templates/model.rb +5 -0
- data/lib/rails/generators/active_record/session_migration/templates/migration.rb +1 -5
- metadata +30 -10
- data/lib/active_record/named_scope.rb +0 -200
|
@@ -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? { |
|
|
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,7 +161,8 @@ 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?)
|
|
117
|
-
became.
|
|
164
|
+
became.instance_variable_set("@errors", errors)
|
|
165
|
+
became.send("#{klass.inheritance_column}=", klass.name) unless self.class.descends_from_active_record?
|
|
118
166
|
became
|
|
119
167
|
end
|
|
120
168
|
|
|
@@ -139,12 +187,18 @@ 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)
|
|
145
195
|
raise ActiveRecordError, "can not update on a new record object" unless persisted?
|
|
196
|
+
|
|
197
|
+
updated_count = self.class.update_all({ name => value }, self.class.primary_key => id)
|
|
198
|
+
|
|
146
199
|
raw_write_attribute(name, value)
|
|
147
|
-
|
|
200
|
+
|
|
201
|
+
updated_count == 1
|
|
148
202
|
end
|
|
149
203
|
|
|
150
204
|
# Updates the attributes of the model from the passed-in hash and saves the
|
|
@@ -312,19 +366,11 @@ module ActiveRecord
|
|
|
312
366
|
|
|
313
367
|
new_id = self.class.unscoped.insert attributes_values
|
|
314
368
|
|
|
315
|
-
self.id ||= new_id
|
|
369
|
+
self.id ||= new_id if self.class.primary_key
|
|
316
370
|
|
|
317
371
|
IdentityMap.add(self) if IdentityMap.enabled?
|
|
318
372
|
@new_record = false
|
|
319
373
|
id
|
|
320
374
|
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
375
|
end
|
|
330
376
|
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
|
|
@@ -65,7 +72,13 @@ module ActiveRecord
|
|
|
65
72
|
# and then establishes the connection.
|
|
66
73
|
initializer "active_record.initialize_database" do |app|
|
|
67
74
|
ActiveSupport.on_load(:active_record) do
|
|
68
|
-
|
|
75
|
+
db_connection_type = "DATABASE_URL"
|
|
76
|
+
unless ENV['DATABASE_URL']
|
|
77
|
+
db_connection_type = "database.yml"
|
|
78
|
+
self.configurations = app.config.database_configuration
|
|
79
|
+
end
|
|
80
|
+
Rails.logger.info "Connecting to database specified by #{db_connection_type}"
|
|
81
|
+
|
|
69
82
|
establish_connection
|
|
70
83
|
end
|
|
71
84
|
end
|
|
@@ -78,15 +91,27 @@ module ActiveRecord
|
|
|
78
91
|
end
|
|
79
92
|
end
|
|
80
93
|
|
|
81
|
-
initializer "active_record.
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
94
|
+
initializer "active_record.set_reloader_hooks" do |app|
|
|
95
|
+
hook = lambda do
|
|
96
|
+
ActiveRecord::Base.clear_reloadable_connections!
|
|
97
|
+
ActiveRecord::Base.clear_cache!
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
if app.config.reload_classes_only_on_change
|
|
101
|
+
ActiveSupport.on_load(:active_record) do
|
|
102
|
+
ActionDispatch::Reloader.to_prepare(&hook)
|
|
103
|
+
end
|
|
104
|
+
else
|
|
105
|
+
ActiveSupport.on_load(:active_record) do
|
|
106
|
+
ActionDispatch::Reloader.to_cleanup(&hook)
|
|
86
107
|
end
|
|
87
108
|
end
|
|
88
109
|
end
|
|
89
110
|
|
|
111
|
+
initializer "active_record.add_watchable_files" do |app|
|
|
112
|
+
config.watchable_files.concat ["#{app.root}/db/schema.rb", "#{app.root}/db/structure.sql"]
|
|
113
|
+
end
|
|
114
|
+
|
|
90
115
|
config.after_initialize do
|
|
91
116
|
ActiveSupport.on_load(:active_record) do
|
|
92
117
|
instantiate_observers
|
|
@@ -96,28 +121,5 @@ module ActiveRecord
|
|
|
96
121
|
end
|
|
97
122
|
end
|
|
98
123
|
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
124
|
end
|
|
123
125
|
end
|
|
@@ -32,7 +32,9 @@ module ActiveRecord
|
|
|
32
32
|
|
|
33
33
|
def append_info_to_payload(payload)
|
|
34
34
|
super
|
|
35
|
-
|
|
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
|