activerecord 4.0.13 → 4.1.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +745 -2700
- data/README.rdoc +2 -2
- data/examples/performance.rb +30 -18
- data/examples/simple.rb +4 -4
- data/lib/active_record.rb +2 -6
- data/lib/active_record/aggregations.rb +2 -1
- data/lib/active_record/association_relation.rb +0 -4
- data/lib/active_record/associations.rb +87 -43
- data/lib/active_record/associations/alias_tracker.rb +1 -3
- data/lib/active_record/associations/association.rb +8 -16
- data/lib/active_record/associations/association_scope.rb +5 -16
- data/lib/active_record/associations/belongs_to_association.rb +34 -25
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +1 -1
- data/lib/active_record/associations/builder/association.rb +78 -54
- data/lib/active_record/associations/builder/belongs_to.rb +91 -58
- data/lib/active_record/associations/builder/collection_association.rb +47 -45
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +107 -25
- data/lib/active_record/associations/builder/has_many.rb +2 -2
- data/lib/active_record/associations/builder/has_one.rb +5 -7
- data/lib/active_record/associations/builder/singular_association.rb +6 -7
- data/lib/active_record/associations/collection_association.rb +68 -105
- data/lib/active_record/associations/collection_proxy.rb +12 -15
- data/lib/active_record/associations/has_many_association.rb +11 -9
- data/lib/active_record/associations/has_many_through_association.rb +16 -12
- data/lib/active_record/associations/has_one_association.rb +1 -1
- data/lib/active_record/associations/join_dependency.rb +204 -165
- data/lib/active_record/associations/join_dependency/join_association.rb +43 -101
- data/lib/active_record/associations/join_dependency/join_base.rb +6 -8
- data/lib/active_record/associations/join_dependency/join_part.rb +18 -37
- data/lib/active_record/associations/join_helper.rb +2 -11
- data/lib/active_record/associations/preloader.rb +89 -34
- data/lib/active_record/associations/preloader/association.rb +43 -25
- data/lib/active_record/associations/preloader/collection_association.rb +2 -2
- data/lib/active_record/associations/preloader/has_many_through.rb +1 -1
- data/lib/active_record/associations/preloader/singular_association.rb +3 -3
- data/lib/active_record/associations/preloader/through_association.rb +58 -26
- data/lib/active_record/associations/singular_association.rb +6 -5
- data/lib/active_record/associations/through_association.rb +2 -2
- data/lib/active_record/attribute_assignment.rb +5 -2
- data/lib/active_record/attribute_methods.rb +45 -40
- data/lib/active_record/attribute_methods/before_type_cast.rb +2 -1
- data/lib/active_record/attribute_methods/dirty.rb +8 -22
- data/lib/active_record/attribute_methods/primary_key.rb +1 -7
- data/lib/active_record/attribute_methods/read.rb +55 -28
- data/lib/active_record/attribute_methods/serialization.rb +12 -33
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +1 -13
- data/lib/active_record/attribute_methods/write.rb +37 -12
- data/lib/active_record/autosave_association.rb +207 -207
- data/lib/active_record/base.rb +5 -1
- data/lib/active_record/callbacks.rb +2 -2
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +2 -7
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +11 -22
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +12 -14
- data/lib/active_record/connection_adapters/abstract/quoting.rb +1 -5
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +21 -0
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +84 -0
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +9 -8
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +52 -83
- data/lib/active_record/connection_adapters/abstract/transaction.rb +0 -5
- data/lib/active_record/connection_adapters/abstract_adapter.rb +14 -97
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +58 -60
- data/lib/active_record/connection_adapters/column.rb +1 -35
- data/lib/active_record/connection_adapters/connection_specification.rb +2 -2
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +3 -4
- data/lib/active_record/connection_adapters/mysql_adapter.rb +16 -15
- data/lib/active_record/connection_adapters/postgresql/array_parser.rb +24 -18
- data/lib/active_record/connection_adapters/postgresql/cast.rb +20 -16
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +23 -43
- data/lib/active_record/connection_adapters/postgresql/oid.rb +19 -12
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +28 -23
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +8 -30
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +92 -75
- data/lib/active_record/connection_adapters/schema_cache.rb +8 -29
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +31 -64
- data/lib/active_record/connection_handling.rb +2 -2
- data/lib/active_record/core.rb +22 -43
- data/lib/active_record/counter_cache.rb +7 -7
- data/lib/active_record/enum.rb +100 -0
- data/lib/active_record/errors.rb +10 -5
- data/lib/active_record/fixture_set/file.rb +2 -1
- data/lib/active_record/fixtures.rb +171 -74
- data/lib/active_record/inheritance.rb +16 -22
- data/lib/active_record/integration.rb +52 -1
- data/lib/active_record/locking/optimistic.rb +7 -2
- data/lib/active_record/locking/pessimistic.rb +1 -1
- data/lib/active_record/log_subscriber.rb +5 -12
- data/lib/active_record/migration.rb +62 -46
- data/lib/active_record/migration/command_recorder.rb +7 -13
- data/lib/active_record/model_schema.rb +7 -14
- data/lib/active_record/nested_attributes.rb +10 -8
- data/lib/active_record/no_touching.rb +52 -0
- data/lib/active_record/null_relation.rb +3 -3
- data/lib/active_record/persistence.rb +16 -34
- data/lib/active_record/querying.rb +14 -12
- data/lib/active_record/railtie.rb +0 -50
- data/lib/active_record/railties/databases.rake +12 -15
- data/lib/active_record/readonly_attributes.rb +0 -6
- data/lib/active_record/reflection.rb +189 -75
- data/lib/active_record/relation.rb +69 -94
- data/lib/active_record/relation/batches.rb +57 -23
- data/lib/active_record/relation/calculations.rb +36 -43
- data/lib/active_record/relation/delegation.rb +54 -39
- data/lib/active_record/relation/finder_methods.rb +107 -62
- data/lib/active_record/relation/merger.rb +7 -20
- data/lib/active_record/relation/predicate_builder.rb +57 -38
- data/lib/active_record/relation/predicate_builder/array_handler.rb +29 -0
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +13 -0
- data/lib/active_record/relation/query_methods.rb +110 -98
- data/lib/active_record/relation/spawn_methods.rb +1 -2
- data/lib/active_record/result.rb +45 -6
- data/lib/active_record/runtime_registry.rb +5 -0
- data/lib/active_record/sanitization.rb +6 -8
- data/lib/active_record/schema_dumper.rb +16 -5
- data/lib/active_record/schema_migration.rb +24 -25
- data/lib/active_record/scoping/default.rb +5 -18
- data/lib/active_record/scoping/named.rb +8 -29
- data/lib/active_record/store.rb +56 -28
- data/lib/active_record/tasks/database_tasks.rb +8 -4
- data/lib/active_record/timestamp.rb +4 -4
- data/lib/active_record/transactions.rb +8 -10
- data/lib/active_record/validations/presence.rb +1 -1
- data/lib/active_record/validations/uniqueness.rb +1 -6
- data/lib/active_record/version.rb +1 -1
- data/lib/rails/generators/active_record.rb +2 -8
- data/lib/rails/generators/active_record/migration.rb +18 -0
- data/lib/rails/generators/active_record/migration/migration_generator.rb +4 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +4 -0
- metadata +32 -45
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +0 -65
- data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +0 -60
- data/lib/active_record/tasks/firebird_database_tasks.rb +0 -56
- data/lib/active_record/tasks/oracle_database_tasks.rb +0 -45
- data/lib/active_record/tasks/sqlserver_database_tasks.rb +0 -48
- data/lib/active_record/test_case.rb +0 -102
data/README.rdoc
CHANGED
@@ -175,7 +175,7 @@ by relying on a number of conventions that make it easy for Active Record to inf
|
|
175
175
|
complex relations and structures from a minimal amount of explicit direction.
|
176
176
|
|
177
177
|
Convention over Configuration:
|
178
|
-
* No XML
|
178
|
+
* No XML files!
|
179
179
|
* Lots of reflection and run-time extension
|
180
180
|
* Magic is not inherently a bad word
|
181
181
|
|
@@ -192,7 +192,7 @@ The latest version of Active Record can be installed with RubyGems:
|
|
192
192
|
|
193
193
|
Source code can be downloaded as part of the Rails project on GitHub:
|
194
194
|
|
195
|
-
* https://github.com/rails/rails/tree/
|
195
|
+
* https://github.com/rails/rails/tree/master/activerecord
|
196
196
|
|
197
197
|
|
198
198
|
== License
|
data/examples/performance.rb
CHANGED
@@ -5,12 +5,12 @@ require 'benchmark/ips'
|
|
5
5
|
TIME = (ENV['BENCHMARK_TIME'] || 20).to_i
|
6
6
|
RECORDS = (ENV['BENCHMARK_RECORDS'] || TIME*1000).to_i
|
7
7
|
|
8
|
-
conn = { :
|
8
|
+
conn = { adapter: 'sqlite3', database: ':memory:' }
|
9
9
|
|
10
10
|
ActiveRecord::Base.establish_connection(conn)
|
11
11
|
|
12
12
|
class User < ActiveRecord::Base
|
13
|
-
connection.create_table :users, :
|
13
|
+
connection.create_table :users, force: true do |t|
|
14
14
|
t.string :name, :email
|
15
15
|
t.timestamps
|
16
16
|
end
|
@@ -19,7 +19,7 @@ class User < ActiveRecord::Base
|
|
19
19
|
end
|
20
20
|
|
21
21
|
class Exhibit < ActiveRecord::Base
|
22
|
-
connection.create_table :exhibits, :
|
22
|
+
connection.create_table :exhibits, force: true do |t|
|
23
23
|
t.belongs_to :user
|
24
24
|
t.string :name
|
25
25
|
t.text :notes
|
@@ -43,6 +43,8 @@ class Exhibit < ActiveRecord::Base
|
|
43
43
|
def self.feel(exhibits) exhibits.each { |e| e.feel } end
|
44
44
|
end
|
45
45
|
|
46
|
+
def progress_bar(int); print "." if (int%100).zero? ; end
|
47
|
+
|
46
48
|
puts 'Generating data...'
|
47
49
|
|
48
50
|
module ActiveRecord
|
@@ -75,30 +77,32 @@ notes = ActiveRecord::Faker::LOREM.join ' '
|
|
75
77
|
today = Date.today
|
76
78
|
|
77
79
|
puts "Inserting #{RECORDS} users and exhibits..."
|
78
|
-
RECORDS.times do
|
80
|
+
RECORDS.times do |record|
|
79
81
|
user = User.create(
|
80
|
-
:
|
81
|
-
:
|
82
|
-
:
|
82
|
+
created_at: today,
|
83
|
+
name: ActiveRecord::Faker.name,
|
84
|
+
email: ActiveRecord::Faker.email
|
83
85
|
)
|
84
86
|
|
85
87
|
Exhibit.create(
|
86
|
-
:
|
87
|
-
:
|
88
|
-
:
|
89
|
-
:
|
88
|
+
created_at: today,
|
89
|
+
name: ActiveRecord::Faker.name,
|
90
|
+
user: user,
|
91
|
+
notes: notes
|
90
92
|
)
|
93
|
+
progress_bar(record)
|
91
94
|
end
|
95
|
+
puts "Done!\n"
|
92
96
|
|
93
97
|
Benchmark.ips(TIME) do |x|
|
94
98
|
ar_obj = Exhibit.find(1)
|
95
|
-
attrs = { :
|
96
|
-
attrs_first = { :
|
97
|
-
attrs_second = { :
|
99
|
+
attrs = { name: 'sam' }
|
100
|
+
attrs_first = { name: 'sam' }
|
101
|
+
attrs_second = { name: 'tom' }
|
98
102
|
exhibit = {
|
99
|
-
:
|
100
|
-
:
|
101
|
-
:
|
103
|
+
name: ActiveRecord::Faker.name,
|
104
|
+
notes: notes,
|
105
|
+
created_at: Date.today
|
102
106
|
}
|
103
107
|
|
104
108
|
x.report("Model#id") do
|
@@ -117,10 +121,18 @@ Benchmark.ips(TIME) do |x|
|
|
117
121
|
Exhibit.first.look
|
118
122
|
end
|
119
123
|
|
124
|
+
x.report 'Model.take' do
|
125
|
+
Exhibit.take
|
126
|
+
end
|
127
|
+
|
120
128
|
x.report("Model.all limit(100)") do
|
121
129
|
Exhibit.look Exhibit.limit(100)
|
122
130
|
end
|
123
131
|
|
132
|
+
x.report("Model.all take(100)") do
|
133
|
+
Exhibit.look Exhibit.take(100)
|
134
|
+
end
|
135
|
+
|
124
136
|
x.report "Model.all limit(100) with relationship" do
|
125
137
|
Exhibit.feel Exhibit.limit(100).includes(:user)
|
126
138
|
end
|
@@ -167,6 +179,6 @@ Benchmark.ips(TIME) do |x|
|
|
167
179
|
end
|
168
180
|
|
169
181
|
x.report "AR.execute(query)" do
|
170
|
-
ActiveRecord::Base.connection.execute("
|
182
|
+
ActiveRecord::Base.connection.execute("SELECT * FROM exhibits WHERE id = #{(rand * 1000 + 1).to_i}")
|
171
183
|
end
|
172
184
|
end
|
data/examples/simple.rb
CHANGED
@@ -1,14 +1,14 @@
|
|
1
|
-
|
1
|
+
require File.expand_path('../../../load_paths', __FILE__)
|
2
2
|
require 'active_record'
|
3
3
|
|
4
4
|
class Person < ActiveRecord::Base
|
5
|
-
establish_connection :
|
6
|
-
connection.create_table table_name, :
|
5
|
+
establish_connection adapter: 'sqlite3', database: 'foobar.db'
|
6
|
+
connection.create_table table_name, force: true do |t|
|
7
7
|
t.string :name
|
8
8
|
end
|
9
9
|
end
|
10
10
|
|
11
|
-
bob = Person.create!(:
|
11
|
+
bob = Person.create!(name: 'bob')
|
12
12
|
puts Person.all.inspect
|
13
13
|
bob.destroy
|
14
14
|
puts Person.all.inspect
|
data/lib/active_record.rb
CHANGED
@@ -25,7 +25,6 @@ require 'active_support'
|
|
25
25
|
require 'active_support/rails'
|
26
26
|
require 'active_model'
|
27
27
|
require 'arel'
|
28
|
-
require 'active_record/deprecated_finders'
|
29
28
|
|
30
29
|
require 'active_record/version'
|
31
30
|
|
@@ -38,6 +37,7 @@ module ActiveRecord
|
|
38
37
|
autoload :ConnectionHandling
|
39
38
|
autoload :CounterCache
|
40
39
|
autoload :DynamicMatchers
|
40
|
+
autoload :Enum
|
41
41
|
autoload :Explain
|
42
42
|
autoload :Inheritance
|
43
43
|
autoload :Integration
|
@@ -45,6 +45,7 @@ module ActiveRecord
|
|
45
45
|
autoload :Migrator, 'active_record/migration'
|
46
46
|
autoload :ModelSchema
|
47
47
|
autoload :NestedAttributes
|
48
|
+
autoload :NoTouching
|
48
49
|
autoload :Persistence
|
49
50
|
autoload :QueryCache
|
50
51
|
autoload :Querying
|
@@ -146,13 +147,8 @@ module ActiveRecord
|
|
146
147
|
autoload :MySQLDatabaseTasks, 'active_record/tasks/mysql_database_tasks'
|
147
148
|
autoload :PostgreSQLDatabaseTasks,
|
148
149
|
'active_record/tasks/postgresql_database_tasks'
|
149
|
-
|
150
|
-
autoload :FirebirdDatabaseTasks, 'active_record/tasks/firebird_database_tasks'
|
151
|
-
autoload :SqlserverDatabaseTasks, 'active_record/tasks/sqlserver_database_tasks'
|
152
|
-
autoload :OracleDatabaseTasks, 'active_record/tasks/oracle_database_tasks'
|
153
150
|
end
|
154
151
|
|
155
|
-
autoload :TestCase
|
156
152
|
autoload :TestFixtures, 'active_record/fixtures'
|
157
153
|
|
158
154
|
def self.eager_load!
|
@@ -223,7 +223,8 @@ module ActiveRecord
|
|
223
223
|
reader_method(name, class_name, mapping, allow_nil, constructor)
|
224
224
|
writer_method(name, class_name, mapping, allow_nil, converter)
|
225
225
|
|
226
|
-
|
226
|
+
reflection = ActiveRecord::Reflection.create(:composed_of, part_id, nil, options, self)
|
227
|
+
Reflection.add_aggregate_reflection self, part_id, reflection
|
227
228
|
end
|
228
229
|
|
229
230
|
private
|
@@ -4,12 +4,6 @@ require 'active_support/core_ext/module/remove_method'
|
|
4
4
|
require 'active_record/errors'
|
5
5
|
|
6
6
|
module ActiveRecord
|
7
|
-
class AssociationNotFoundError < ConfigurationError #:nodoc:
|
8
|
-
def initialize(record, association_name)
|
9
|
-
super("Association named '#{association_name}' was not found on #{record.class.name}; perhaps you misspelled it?")
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
7
|
class InverseOfAssociationNotFoundError < ActiveRecordError #:nodoc:
|
14
8
|
def initialize(reflection, associated_class = nil)
|
15
9
|
super("Could not find the inverse association for #{reflection.name} (#{reflection.options[:inverse_of].inspect} in #{associated_class.nil? ? reflection.class_name : associated_class.name})")
|
@@ -79,12 +73,6 @@ module ActiveRecord
|
|
79
73
|
end
|
80
74
|
end
|
81
75
|
|
82
|
-
class HasAndBelongsToManyAssociationForeignKeyNeeded < ActiveRecordError #:nodoc:
|
83
|
-
def initialize(reflection)
|
84
|
-
super("Cannot create self referential has_and_belongs_to_many association on '#{reflection.class_name rescue nil}##{reflection.name rescue nil}'. :association_foreign_key cannot be the same as the :foreign_key.")
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
76
|
class EagerLoadPolymorphicError < ActiveRecordError #:nodoc:
|
89
77
|
def initialize(reflection)
|
90
78
|
super("Can not eagerly load the polymorphic association #{reflection.name.inspect}")
|
@@ -120,7 +108,6 @@ module ActiveRecord
|
|
120
108
|
|
121
109
|
autoload :BelongsToAssociation, 'active_record/associations/belongs_to_association'
|
122
110
|
autoload :BelongsToPolymorphicAssociation, 'active_record/associations/belongs_to_polymorphic_association'
|
123
|
-
autoload :HasAndBelongsToManyAssociation, 'active_record/associations/has_and_belongs_to_many_association'
|
124
111
|
autoload :HasManyAssociation, 'active_record/associations/has_many_association'
|
125
112
|
autoload :HasManyThroughAssociation, 'active_record/associations/has_many_through_association'
|
126
113
|
autoload :HasOneAssociation, 'active_record/associations/has_one_association'
|
@@ -159,7 +146,7 @@ module ActiveRecord
|
|
159
146
|
association = association_instance_get(name)
|
160
147
|
|
161
148
|
if association.nil?
|
162
|
-
|
149
|
+
reflection = self.class.reflect_on_association(name)
|
163
150
|
association = reflection.association_class.new(self, reflection)
|
164
151
|
association_instance_set(name, association)
|
165
152
|
end
|
@@ -170,7 +157,7 @@ module ActiveRecord
|
|
170
157
|
private
|
171
158
|
# Returns the specified association instance if it responds to :loaded?, nil otherwise.
|
172
159
|
def association_instance_get(name)
|
173
|
-
@association_cache[name
|
160
|
+
@association_cache[name]
|
174
161
|
end
|
175
162
|
|
176
163
|
# Set the specified association instance.
|
@@ -178,7 +165,7 @@ module ActiveRecord
|
|
178
165
|
@association_cache[name] = association
|
179
166
|
end
|
180
167
|
|
181
|
-
# Associations are a set of macro-like class methods for tying objects together through
|
168
|
+
# \Associations are a set of macro-like class methods for tying objects together through
|
182
169
|
# foreign keys. They express relationships like "Project has one Project Manager"
|
183
170
|
# or "Project belongs to a Portfolio". Each macro adds a number of methods to the
|
184
171
|
# class which are specialized according to the collection or association symbol and the
|
@@ -371,11 +358,11 @@ module ActiveRecord
|
|
371
358
|
# there is some special behavior you should be aware of, mostly involving the saving of
|
372
359
|
# associated objects.
|
373
360
|
#
|
374
|
-
# You can set the
|
361
|
+
# You can set the <tt>:autosave</tt> option on a <tt>has_one</tt>, <tt>belongs_to</tt>,
|
375
362
|
# <tt>has_many</tt>, or <tt>has_and_belongs_to_many</tt> association. Setting it
|
376
363
|
# to +true+ will _always_ save the members, whereas setting it to +false+ will
|
377
|
-
# _never_ save the members. More details about
|
378
|
-
#
|
364
|
+
# _never_ save the members. More details about <tt>:autosave</tt> option is available at
|
365
|
+
# AutosaveAssociation.
|
379
366
|
#
|
380
367
|
# === One-to-one associations
|
381
368
|
#
|
@@ -408,7 +395,7 @@ module ActiveRecord
|
|
408
395
|
#
|
409
396
|
# == Customizing the query
|
410
397
|
#
|
411
|
-
# Associations are built from <tt>Relation</tt>s, and you can use the <tt>Relation</tt> syntax
|
398
|
+
# \Associations are built from <tt>Relation</tt>s, and you can use the <tt>Relation</tt> syntax
|
412
399
|
# to customize them. For example, to add a condition:
|
413
400
|
#
|
414
401
|
# class Blog < ActiveRecord::Base
|
@@ -574,6 +561,8 @@ module ActiveRecord
|
|
574
561
|
# @group.avatars << Avatar.new # this would work if User belonged_to Avatar rather than the other way around
|
575
562
|
# @group.avatars.delete(@group.avatars.last) # so would this
|
576
563
|
#
|
564
|
+
# == Setting Inverses
|
565
|
+
#
|
577
566
|
# If you are using a +belongs_to+ on the join model, it is a good idea to set the
|
578
567
|
# <tt>:inverse_of</tt> option on the +belongs_to+, which will mean that the following example
|
579
568
|
# works correctly (where <tt>tags</tt> is a +has_many+ <tt>:through</tt> association):
|
@@ -590,7 +579,27 @@ module ActiveRecord
|
|
590
579
|
# belongs_to :tag, inverse_of: :taggings
|
591
580
|
# end
|
592
581
|
#
|
593
|
-
#
|
582
|
+
# If you do not set the <tt>:inverse_of</tt> record, the association will
|
583
|
+
# do its best to match itself up with the correct inverse. Automatic
|
584
|
+
# inverse detection only works on <tt>has_many</tt>, <tt>has_one</tt>, and
|
585
|
+
# <tt>belongs_to</tt> associations.
|
586
|
+
#
|
587
|
+
# Extra options on the associations, as defined in the
|
588
|
+
# <tt>AssociationReflection::INVALID_AUTOMATIC_INVERSE_OPTIONS</tt> constant, will
|
589
|
+
# also prevent the association's inverse from being found automatically.
|
590
|
+
#
|
591
|
+
# The automatic guessing of the inverse association uses a heuristic based
|
592
|
+
# on the name of the class, so it may not work for all associations,
|
593
|
+
# especially the ones with non-standard names.
|
594
|
+
#
|
595
|
+
# You can turn off the automatic detection of inverse associations by setting
|
596
|
+
# the <tt>:inverse_of</tt> option to <tt>false</tt> like so:
|
597
|
+
#
|
598
|
+
# class Taggable < ActiveRecord::Base
|
599
|
+
# belongs_to :tag, inverse_of: false
|
600
|
+
# end
|
601
|
+
#
|
602
|
+
# == Nested \Associations
|
594
603
|
#
|
595
604
|
# You can actually specify *any* association with the <tt>:through</tt> option, including an
|
596
605
|
# association which has a <tt>:through</tt> option itself. For example:
|
@@ -633,7 +642,7 @@ module ActiveRecord
|
|
633
642
|
# add a <tt>Commenter</tt> in the example above, there would be no way to tell how to set up the
|
634
643
|
# intermediate <tt>Post</tt> and <tt>Comment</tt> objects.
|
635
644
|
#
|
636
|
-
# == Polymorphic Associations
|
645
|
+
# == Polymorphic \Associations
|
637
646
|
#
|
638
647
|
# Polymorphic associations on models are not restricted on what types of models they
|
639
648
|
# can be associated with. Rather, they specify an interface that a +has_many+ association
|
@@ -663,8 +672,8 @@ module ActiveRecord
|
|
663
672
|
# class Asset < ActiveRecord::Base
|
664
673
|
# belongs_to :attachable, polymorphic: true
|
665
674
|
#
|
666
|
-
# def attachable_type=(
|
667
|
-
# super(
|
675
|
+
# def attachable_type=(sType)
|
676
|
+
# super(sType.to_s.classify.constantize.base_class.to_s)
|
668
677
|
# end
|
669
678
|
# end
|
670
679
|
#
|
@@ -795,7 +804,7 @@ module ActiveRecord
|
|
795
804
|
# For example if all the addressables are either of class Person or Company then a total
|
796
805
|
# of 3 queries will be executed. The list of addressable types to load is determined on
|
797
806
|
# the back of the addresses loaded. This is not supported if Active Record has to fallback
|
798
|
-
# to the previous implementation of eager loading and will raise ActiveRecord::EagerLoadPolymorphicError
|
807
|
+
# to the previous implementation of eager loading and will raise <tt>ActiveRecord::EagerLoadPolymorphicError</tt>.
|
799
808
|
# The reason is that the parent model's type is a column value so its corresponding table
|
800
809
|
# name cannot be put in the +FROM+/+JOIN+ clauses of that query.
|
801
810
|
#
|
@@ -1030,7 +1039,7 @@ module ActiveRecord
|
|
1030
1039
|
# An empty array is returned if none are found.
|
1031
1040
|
# [collection<<(object, ...)]
|
1032
1041
|
# Adds one or more objects to the collection by setting their foreign keys to the collection's primary key.
|
1033
|
-
# Note that this operation instantly fires update
|
1042
|
+
# Note that this operation instantly fires update SQL without waiting for the save or update call on the
|
1034
1043
|
# parent object, unless the parent object is a new record.
|
1035
1044
|
# [collection.delete(object, ...)]
|
1036
1045
|
# Removes one or more objects from the collection by setting their foreign keys to +NULL+.
|
@@ -1066,10 +1075,10 @@ module ActiveRecord
|
|
1066
1075
|
# [collection.size]
|
1067
1076
|
# Returns the number of associated objects.
|
1068
1077
|
# [collection.find(...)]
|
1069
|
-
# Finds an associated object according to the same rules as ActiveRecord::Base.find
|
1078
|
+
# Finds an associated object according to the same rules as <tt>ActiveRecord::Base.find</tt>.
|
1070
1079
|
# [collection.exists?(...)]
|
1071
1080
|
# Checks whether an associated object with the given conditions exists.
|
1072
|
-
# Uses the same rules as ActiveRecord::Base.exists
|
1081
|
+
# Uses the same rules as <tt>ActiveRecord::Base.exists?</tt>.
|
1073
1082
|
# [collection.build(attributes = {}, ...)]
|
1074
1083
|
# Returns one or more new objects of the collection type that have been instantiated
|
1075
1084
|
# with +attributes+ and linked to this object through a foreign key, but have not yet
|
@@ -1088,7 +1097,7 @@ module ActiveRecord
|
|
1088
1097
|
#
|
1089
1098
|
# === Example
|
1090
1099
|
#
|
1091
|
-
#
|
1100
|
+
# A <tt>Firm</tt> class declares <tt>has_many :clients</tt>, which will add:
|
1092
1101
|
# * <tt>Firm#clients</tt> (similar to <tt>Client.where(firm_id: id)</tt>)
|
1093
1102
|
# * <tt>Firm#clients<<</tt>
|
1094
1103
|
# * <tt>Firm#clients.delete</tt>
|
@@ -1122,8 +1131,8 @@ module ActiveRecord
|
|
1122
1131
|
# Controls what happens to the associated objects when
|
1123
1132
|
# their owner is destroyed. Note that these are implemented as
|
1124
1133
|
# callbacks, and Rails executes callbacks in order. Therefore, other
|
1125
|
-
# similar callbacks may affect the
|
1126
|
-
#
|
1134
|
+
# similar callbacks may affect the <tt>:dependent</tt> behavior, and the
|
1135
|
+
# <tt>:dependent</tt> behavior may affect other callbacks.
|
1127
1136
|
#
|
1128
1137
|
# * <tt>:destroy</tt> causes all the associated objects to also be destroyed.
|
1129
1138
|
# * <tt>:delete_all</tt> causes all the associated objects to be deleted directly from the database (so callbacks will not be executed).
|
@@ -1169,8 +1178,8 @@ module ActiveRecord
|
|
1169
1178
|
# If true, always save the associated objects or destroy them if marked for destruction,
|
1170
1179
|
# when saving the parent object. If false, never save or destroy the associated objects.
|
1171
1180
|
# By default, only save associated objects that are new records. This option is implemented as a
|
1172
|
-
# before_save callback. Because callbacks are run in the order they are defined, associated objects
|
1173
|
-
# may need to be explicitly saved in any user-defined before_save callbacks.
|
1181
|
+
# +before_save+ callback. Because callbacks are run in the order they are defined, associated objects
|
1182
|
+
# may need to be explicitly saved in any user-defined +before_save+ callbacks.
|
1174
1183
|
#
|
1175
1184
|
# Note that <tt>accepts_nested_attributes_for</tt> sets <tt>:autosave</tt> to <tt>true</tt>.
|
1176
1185
|
# [:inverse_of]
|
@@ -1189,13 +1198,14 @@ module ActiveRecord
|
|
1189
1198
|
# has_many :reports, -> { readonly }
|
1190
1199
|
# has_many :subscribers, through: :subscriptions, source: :user
|
1191
1200
|
def has_many(name, scope = nil, options = {}, &extension)
|
1192
|
-
Builder::HasMany.build(self, name, scope, options, &extension)
|
1201
|
+
reflection = Builder::HasMany.build(self, name, scope, options, &extension)
|
1202
|
+
Reflection.add_reflection self, name, reflection
|
1193
1203
|
end
|
1194
1204
|
|
1195
1205
|
# Specifies a one-to-one association with another class. This method should only be used
|
1196
1206
|
# if the other class contains the foreign key. If the current class contains the foreign key,
|
1197
1207
|
# then you should use +belongs_to+ instead. See also ActiveRecord::Associations::ClassMethods's overview
|
1198
|
-
# on when to use has_one and when to use belongs_to
|
1208
|
+
# on when to use +has_one+ and when to use +belongs_to+.
|
1199
1209
|
#
|
1200
1210
|
# The following methods for retrieval and query of a single associated object will be added:
|
1201
1211
|
#
|
@@ -1292,7 +1302,8 @@ module ActiveRecord
|
|
1292
1302
|
# has_one :club, through: :membership
|
1293
1303
|
# has_one :primary_address, -> { where primary: true }, through: :addressables, source: :addressable
|
1294
1304
|
def has_one(name, scope = nil, options = {})
|
1295
|
-
Builder::HasOne.build(self, name, scope, options)
|
1305
|
+
reflection = Builder::HasOne.build(self, name, scope, options)
|
1306
|
+
Reflection.add_reflection self, name, reflection
|
1296
1307
|
end
|
1297
1308
|
|
1298
1309
|
# Specifies a one-to-one association with another class. This method should only be used
|
@@ -1363,7 +1374,7 @@ module ActiveRecord
|
|
1363
1374
|
# class is created and decremented when it's destroyed. This requires that a column
|
1364
1375
|
# named <tt>#{table_name}_count</tt> (such as +comments_count+ for a belonging Comment class)
|
1365
1376
|
# is used on the associate class (such as a Post class) - that is the migration for
|
1366
|
-
# <tt>#{table_name}_count</tt> is created on the associate class (such that Post.comments_count will
|
1377
|
+
# <tt>#{table_name}_count</tt> is created on the associate class (such that <tt>Post.comments_count</tt> will
|
1367
1378
|
# return the count cached, see note below). You can also specify a custom counter
|
1368
1379
|
# cache column by providing a column name instead of a +true+/+false+ value to this
|
1369
1380
|
# option (e.g., <tt>counter_cache: :my_custom_counter</tt>.)
|
@@ -1396,7 +1407,7 @@ module ActiveRecord
|
|
1396
1407
|
# belongs_to :firm, foreign_key: "client_of"
|
1397
1408
|
# belongs_to :person, primary_key: "name", foreign_key: "person_name"
|
1398
1409
|
# belongs_to :author, class_name: "Person", foreign_key: "author_id"
|
1399
|
-
# belongs_to :valid_coupon, ->(o) { where "discounts >
|
1410
|
+
# belongs_to :valid_coupon, ->(o) { where "discounts > #{o.payments_count}" },
|
1400
1411
|
# class_name: "Coupon", foreign_key: "coupon_id"
|
1401
1412
|
# belongs_to :attachable, polymorphic: true
|
1402
1413
|
# belongs_to :project, readonly: true
|
@@ -1404,7 +1415,8 @@ module ActiveRecord
|
|
1404
1415
|
# belongs_to :company, touch: true
|
1405
1416
|
# belongs_to :company, touch: :employees_last_updated_at
|
1406
1417
|
def belongs_to(name, scope = nil, options = {})
|
1407
|
-
Builder::BelongsTo.build(self, name, scope, options)
|
1418
|
+
reflection = Builder::BelongsTo.build(self, name, scope, options)
|
1419
|
+
Reflection.add_reflection self, name, reflection
|
1408
1420
|
end
|
1409
1421
|
|
1410
1422
|
# Specifies a many-to-many relationship with another class. This associates two classes via an
|
@@ -1445,7 +1457,7 @@ module ActiveRecord
|
|
1445
1457
|
# [collection<<(object, ...)]
|
1446
1458
|
# Adds one or more objects to the collection by creating associations in the join table
|
1447
1459
|
# (<tt>collection.push</tt> and <tt>collection.concat</tt> are aliases to this method).
|
1448
|
-
# Note that this operation instantly fires update
|
1460
|
+
# Note that this operation instantly fires update SQL without waiting for the save or update call on the
|
1449
1461
|
# parent object, unless the parent object is a new record.
|
1450
1462
|
# [collection.delete(object, ...)]
|
1451
1463
|
# Removes one or more objects from the collection by removing their associations from the join table.
|
@@ -1468,10 +1480,10 @@ module ActiveRecord
|
|
1468
1480
|
# [collection.find(id)]
|
1469
1481
|
# Finds an associated object responding to the +id+ and that
|
1470
1482
|
# meets the condition that it has to be associated with this object.
|
1471
|
-
# Uses the same rules as ActiveRecord::Base.find
|
1483
|
+
# Uses the same rules as <tt>ActiveRecord::Base.find</tt>.
|
1472
1484
|
# [collection.exists?(...)]
|
1473
1485
|
# Checks whether an associated object with the given conditions exists.
|
1474
|
-
# Uses the same rules as ActiveRecord::Base.exists
|
1486
|
+
# Uses the same rules as <tt>ActiveRecord::Base.exists?</tt>.
|
1475
1487
|
# [collection.build(attributes = {})]
|
1476
1488
|
# Returns a new object of the collection type that has been instantiated
|
1477
1489
|
# with +attributes+ and linked to this object through the join table, but has not yet been saved.
|
@@ -1541,7 +1553,39 @@ module ActiveRecord
|
|
1541
1553
|
# has_and_belongs_to_many :categories, join_table: "prods_cats"
|
1542
1554
|
# has_and_belongs_to_many :categories, -> { readonly }
|
1543
1555
|
def has_and_belongs_to_many(name, scope = nil, options = {}, &extension)
|
1544
|
-
|
1556
|
+
if scope.is_a?(Hash)
|
1557
|
+
options = scope
|
1558
|
+
scope = nil
|
1559
|
+
end
|
1560
|
+
|
1561
|
+
builder = Builder::HasAndBelongsToMany.new name, self, options
|
1562
|
+
|
1563
|
+
join_model = builder.through_model
|
1564
|
+
|
1565
|
+
middle_reflection = builder.middle_reflection join_model
|
1566
|
+
|
1567
|
+
Builder::HasMany.define_callbacks self, middle_reflection
|
1568
|
+
Reflection.add_reflection self, middle_reflection.name, middle_reflection
|
1569
|
+
|
1570
|
+
include Module.new {
|
1571
|
+
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
1572
|
+
def destroy_associations
|
1573
|
+
association(:#{middle_reflection.name}).delete_all(:delete_all)
|
1574
|
+
association(:#{name}).reset
|
1575
|
+
super
|
1576
|
+
end
|
1577
|
+
RUBY
|
1578
|
+
}
|
1579
|
+
|
1580
|
+
hm_options = {}
|
1581
|
+
hm_options[:through] = middle_reflection.name
|
1582
|
+
hm_options[:source] = join_model.right_reflection.name
|
1583
|
+
|
1584
|
+
[:before_add, :after_add, :before_remove, :after_remove].each do |k|
|
1585
|
+
hm_options[k] = options[k] if options.key? k
|
1586
|
+
end
|
1587
|
+
|
1588
|
+
has_many name, scope, hm_options, &extension
|
1545
1589
|
end
|
1546
1590
|
end
|
1547
1591
|
end
|