activerecord 2.0.2 → 2.0.4
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.
- data/CHANGELOG +25 -0
- data/README +0 -0
- data/Rakefile +5 -3
- data/lib/active_record.rb +0 -0
- data/lib/active_record/associations.rb +232 -193
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +14 -14
- data/lib/active_record/associations/has_many_association.rb +2 -2
- data/lib/active_record/associations/has_many_through_association.rb +25 -6
- data/lib/active_record/attribute_methods.rb +4 -3
- data/lib/active_record/base.rb +75 -41
- data/lib/active_record/calculations.rb +2 -1
- data/lib/active_record/callbacks.rb +0 -0
- data/lib/active_record/connection_adapters/abstract/connection_specification.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +8 -6
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +12 -11
- data/lib/active_record/connection_adapters/abstract_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +3 -3
- data/lib/active_record/connection_adapters/sqlite_adapter.rb +13 -6
- data/lib/active_record/fixtures.rb +29 -31
- data/lib/active_record/migration.rb +4 -5
- data/lib/active_record/observer.rb +1 -1
- data/lib/active_record/transactions.rb +3 -5
- data/lib/active_record/validations.rb +5 -3
- data/lib/active_record/version.rb +1 -1
- data/test/abstract_unit.rb +0 -0
- data/test/active_schema_test_mysql.rb +5 -2
- data/test/adapter_test.rb +1 -0
- data/test/all.sh +0 -0
- data/test/associations/callbacks_test.rb +1 -1
- data/test/associations/eager_test.rb +5 -0
- data/test/associations/join_model_test.rb +11 -3
- data/test/associations_test.rb +36 -6
- data/test/attribute_methods_test.rb +0 -0
- data/test/base_test.rb +92 -10
- data/test/calculations_test.rb +9 -1
- data/test/debug.log +358 -0
- data/test/deprecated_finder_test.rb +0 -0
- data/test/fixtures/author.rb +1 -1
- data/test/fixtures/company.rb +0 -0
- data/test/fixtures/fixture_database.sqlite3 +0 -0
- data/test/fixtures/fixture_database_2.sqlite3 +0 -0
- data/test/fixtures/reply.rb +0 -0
- data/test/fixtures/topic.rb +0 -0
- data/test/fixtures_test.rb +20 -12
- data/test/inheritance_test.rb +0 -0
- data/test/lifecycle_test.rb +0 -0
- data/test/migration_test.rb +46 -0
- data/test/query_cache_test.rb +22 -2
- data/test/readonly_test.rb +0 -0
- data/test/unconnected_test.rb +0 -0
- data/test/validations_test.rb +50 -38
- metadata +8 -4
data/CHANGELOG
CHANGED
@@ -1,3 +1,28 @@
|
|
1
|
+
*2.0.4* (2nd September 2008)
|
2
|
+
|
3
|
+
* Migrations: create_table supports primary_key_prefix_type. #10314 [student, thechrisoshow]
|
4
|
+
|
5
|
+
* Ensure that ActiveRecord::Calculations disambiguates field names with the table name. #11027 [cavalle]
|
6
|
+
|
7
|
+
* Ensure that modifying has_and_belongs_to_many actions clear the query cache. Closes #10840 [john.andrews]
|
8
|
+
|
9
|
+
* Fix issue where Table#references doesn't pass a :null option to a *_type attribute for polymorphic associations. Closes #10753 [railsjitsu]
|
10
|
+
|
11
|
+
* update_all ignores scoped :order and :limit, so post.comments.update_all doesn't try to include the comment order in the update statement. #10686 [Brendan Ribera]
|
12
|
+
|
13
|
+
* Added by parameter to increment, decrement, and their bang varieties so you can do player1.increment!(:points, 5) #10542 [Sam]
|
14
|
+
|
15
|
+
* Optimize ActiveRecord::Base#exists? to use #select_all instead of #find. Closes #10605 [jamesh, fcheung, protocool]
|
16
|
+
|
17
|
+
* Don't unnecessarily load has_many associations in after_update callbacks. Closes #6822 [stopdropandrew, canadaduane]
|
18
|
+
|
19
|
+
* Eager belongs_to :include infers the foreign key from the association name rather than the class name. #10517 [Jonathan Viney]
|
20
|
+
|
21
|
+
* SQLite: fix rename_ and remove_column for columns with unique indexes. #10576 [Brandon Keepers]
|
22
|
+
|
23
|
+
* Ruby 1.9 compatibility. [Jeremy Kemper]
|
24
|
+
|
25
|
+
|
1
26
|
*2.0.2* (December 16th, 2007)
|
2
27
|
|
3
28
|
* Ensure optimistic locking handles nil #lock_version values properly. Closes #10510 [rick]
|
data/README
CHANGED
File without changes
|
data/Rakefile
CHANGED
@@ -4,6 +4,7 @@ require 'rake/testtask'
|
|
4
4
|
require 'rake/rdoctask'
|
5
5
|
require 'rake/packagetask'
|
6
6
|
require 'rake/gempackagetask'
|
7
|
+
require 'rake/contrib/sshpublisher'
|
7
8
|
require 'rake/contrib/rubyforgepublisher'
|
8
9
|
require File.join(File.dirname(__FILE__), 'lib', 'active_record', 'version')
|
9
10
|
|
@@ -173,7 +174,7 @@ spec = Gem::Specification.new do |s|
|
|
173
174
|
s.files = s.files + Dir.glob( "#{dir}/**/*" ).delete_if { |item| item.include?( "\.svn" ) }
|
174
175
|
end
|
175
176
|
|
176
|
-
s.add_dependency('activesupport', '= 2.0.
|
177
|
+
s.add_dependency('activesupport', '= 2.0.4' + PKG_BUILD)
|
177
178
|
|
178
179
|
s.files.delete "test/fixtures/fixture_database.sqlite"
|
179
180
|
s.files.delete "test/fixtures/fixture_database_2.sqlite"
|
@@ -227,8 +228,8 @@ end
|
|
227
228
|
|
228
229
|
desc "Publish the beta gem"
|
229
230
|
task :pgem => [:package] do
|
230
|
-
Rake::SshFilePublisher.new("
|
231
|
-
`ssh
|
231
|
+
Rake::SshFilePublisher.new("david@greed.loudthinking.com", "/u/sites/gems/gems", "pkg", "#{PKG_FILE_NAME}.gem").upload
|
232
|
+
`ssh david@greed.loudthinking.com '/u/sites/gems/gemupdate.sh'`
|
232
233
|
end
|
233
234
|
|
234
235
|
desc "Publish the API documentation"
|
@@ -239,6 +240,7 @@ end
|
|
239
240
|
desc "Publish the release files to RubyForge."
|
240
241
|
task :release => [ :package ] do
|
241
242
|
require 'rubyforge'
|
243
|
+
require 'rake/contrib/rubyforgepublisher'
|
242
244
|
|
243
245
|
packages = %w( gem tgz zip ).collect{ |ext| "pkg/#{PKG_NAME}-#{PKG_VERSION}.#{ext}" }
|
244
246
|
|
data/lib/active_record.rb
CHANGED
File without changes
|
@@ -19,13 +19,13 @@ module ActiveRecord
|
|
19
19
|
super("Cannot have a has_many :through association '#{owner_class_name}##{reflection.name}' on the polymorphic object '#{source_reflection.class_name}##{source_reflection.name}'.")
|
20
20
|
end
|
21
21
|
end
|
22
|
-
|
22
|
+
|
23
23
|
class HasManyThroughAssociationPointlessSourceTypeError < ActiveRecordError #:nodoc:
|
24
24
|
def initialize(owner_class_name, reflection, source_reflection)
|
25
25
|
super("Cannot have a has_many :through association '#{owner_class_name}##{reflection.name}' with a :source_type option if the '#{reflection.through_reflection.class_name}##{source_reflection.name}' is not polymorphic. Try removing :source_type on your association.")
|
26
26
|
end
|
27
27
|
end
|
28
|
-
|
28
|
+
|
29
29
|
class HasManyThroughSourceAssociationNotFoundError < ActiveRecordError #:nodoc:
|
30
30
|
def initialize(reflection)
|
31
31
|
through_reflection = reflection.through_reflection
|
@@ -72,21 +72,21 @@ module ActiveRecord
|
|
72
72
|
base.extend(ClassMethods)
|
73
73
|
end
|
74
74
|
|
75
|
-
# Clears out the association cache
|
75
|
+
# Clears out the association cache
|
76
76
|
def clear_association_cache #:nodoc:
|
77
77
|
self.class.reflect_on_all_associations.to_a.each do |assoc|
|
78
78
|
instance_variable_set "@#{assoc.name}", nil
|
79
79
|
end unless self.new_record?
|
80
80
|
end
|
81
|
-
|
82
|
-
# Associations are a set of macro-like class methods for tying objects together through foreign keys. They express relationships like
|
83
|
-
# "Project has one Project Manager" or "Project belongs to a Portfolio". Each macro adds a number of methods to the class which are
|
84
|
-
# specialized according to the collection or association symbol and the options hash. It works much the same way as Ruby's own <tt>attr*</tt>
|
81
|
+
|
82
|
+
# Associations are a set of macro-like class methods for tying objects together through foreign keys. They express relationships like
|
83
|
+
# "Project has one Project Manager" or "Project belongs to a Portfolio". Each macro adds a number of methods to the class which are
|
84
|
+
# specialized according to the collection or association symbol and the options hash. It works much the same way as Ruby's own <tt>attr*</tt>
|
85
85
|
# methods. Example:
|
86
86
|
#
|
87
87
|
# class Project < ActiveRecord::Base
|
88
88
|
# belongs_to :portfolio
|
89
|
-
# has_one :project_manager
|
89
|
+
# has_one :project_manager
|
90
90
|
# has_many :milestones
|
91
91
|
# has_and_belongs_to_many :categories
|
92
92
|
# end
|
@@ -117,38 +117,38 @@ module ActiveRecord
|
|
117
117
|
# #build_other(attributes={}) | X | | X
|
118
118
|
# #create_other(attributes={}) | X | | X
|
119
119
|
# #other.create!(attributes={}) | | | X
|
120
|
-
# #other.nil? | X | X |
|
120
|
+
# #other.nil? | X | X |
|
121
121
|
#
|
122
122
|
# ===Collection associations (one-to-many / many-to-many)
|
123
123
|
# | | | has_many
|
124
|
-
# generated methods | habtm | has_many | :through
|
124
|
+
# generated methods | habtm | has_many | :through
|
125
125
|
# ----------------------------------+-------+----------+----------
|
126
126
|
# #others | X | X | X
|
127
|
-
# #others=(other,other,...) | X | X |
|
127
|
+
# #others=(other,other,...) | X | X |
|
128
128
|
# #other_ids | X | X | X
|
129
|
-
# #other_ids=(id,id,...) | X | X |
|
129
|
+
# #other_ids=(id,id,...) | X | X |
|
130
130
|
# #others<< | X | X | X
|
131
131
|
# #others.push | X | X | X
|
132
132
|
# #others.concat | X | X | X
|
133
|
-
# #others.build(attributes={}) | X | X |
|
134
|
-
# #others.create(attributes={}) | X | X |
|
133
|
+
# #others.build(attributes={}) | X | X |
|
134
|
+
# #others.create(attributes={}) | X | X |
|
135
135
|
# #others.create!(attributes={}) | X | X | X
|
136
136
|
# #others.size | X | X | X
|
137
137
|
# #others.length | X | X | X
|
138
138
|
# #others.count | | X | X
|
139
139
|
# #others.sum(args*,&block) | X | X | X
|
140
140
|
# #others.empty? | X | X | X
|
141
|
-
# #others.clear | X | X |
|
141
|
+
# #others.clear | X | X |
|
142
142
|
# #others.delete(other,other,...) | X | X | X
|
143
|
-
# #others.delete_all | X | X |
|
143
|
+
# #others.delete_all | X | X |
|
144
144
|
# #others.destroy_all | X | X | X
|
145
145
|
# #others.find(*args) | X | X | X
|
146
|
-
# #others.find_first | X | |
|
147
|
-
# #others.uniq | X | X |
|
146
|
+
# #others.find_first | X | |
|
147
|
+
# #others.uniq | X | X |
|
148
148
|
# #others.reset | X | X | X
|
149
149
|
#
|
150
150
|
# == Cardinality and associations
|
151
|
-
#
|
151
|
+
#
|
152
152
|
# ActiveRecord associations can be used to describe relations with one-to-one, one-to-many
|
153
153
|
# and many-to-many cardinality. Each model uses an association to describe its role in
|
154
154
|
# the relation. In each case, the +belongs_to+ association is used in the model that has
|
@@ -207,7 +207,7 @@ module ActiveRecord
|
|
207
207
|
# end
|
208
208
|
#
|
209
209
|
# Choosing which way to build a many-to-many relationship is not always simple.
|
210
|
-
# If you need to work with the relationship model as its own entity,
|
210
|
+
# If you need to work with the relationship model as its own entity,
|
211
211
|
# use <tt>has_many :through</tt>. Use +has_and_belongs_to_many+ when working with legacy schemas or when
|
212
212
|
# you never work directly with the relationship itself.
|
213
213
|
#
|
@@ -253,7 +253,7 @@ module ActiveRecord
|
|
253
253
|
# * If either of these saves fail (due to one of the objects being invalid) the assignment statement returns +false+ and the assignment
|
254
254
|
# is cancelled.
|
255
255
|
# * If you wish to assign an object to a +has_one+ association without saving it, use the <tt>#association.build</tt> method (documented below).
|
256
|
-
# * Assigning an object to a +belongs_to+ association does not save the object, since the foreign key field belongs on the parent. It
|
256
|
+
# * Assigning an object to a +belongs_to+ association does not save the object, since the foreign key field belongs on the parent. It
|
257
257
|
# does not save the parent either.
|
258
258
|
#
|
259
259
|
# === Collections
|
@@ -275,10 +275,10 @@ module ActiveRecord
|
|
275
275
|
# def evaluate_velocity(developer)
|
276
276
|
# ...
|
277
277
|
# end
|
278
|
-
# end
|
278
|
+
# end
|
279
279
|
#
|
280
280
|
# It's possible to stack callbacks by passing them as an array. Example:
|
281
|
-
#
|
281
|
+
#
|
282
282
|
# class Project
|
283
283
|
# has_and_belongs_to_many :developers, :after_add => [:evaluate_velocity, Proc.new { |p, d| p.shipping_date = Time.now}]
|
284
284
|
# end
|
@@ -334,43 +334,43 @@ module ActiveRecord
|
|
334
334
|
#
|
335
335
|
# Some extensions can only be made to work with knowledge of the association proxy's internals.
|
336
336
|
# Extensions can access relevant state using accessors on the association proxy:
|
337
|
-
#
|
337
|
+
#
|
338
338
|
# * +proxy_owner+ - Returns the object the association is part of.
|
339
339
|
# * +proxy_reflection+ - Returns the reflection object that describes the association.
|
340
340
|
# * +proxy_target+ - Returns the associated object for +belongs_to+ and +has_one+, or the collection of associated objects for +has_many+ and +has_and_belongs_to_many+.
|
341
341
|
#
|
342
342
|
# === Association Join Models
|
343
|
-
#
|
343
|
+
#
|
344
344
|
# Has Many associations can be configured with the <tt>:through</tt> option to use an explicit join model to retrieve the data. This
|
345
345
|
# operates similarly to a +has_and_belongs_to_many+ association. The advantage is that you're able to add validations,
|
346
346
|
# callbacks, and extra attributes on the join model. Consider the following schema:
|
347
|
-
#
|
347
|
+
#
|
348
348
|
# class Author < ActiveRecord::Base
|
349
349
|
# has_many :authorships
|
350
350
|
# has_many :books, :through => :authorships
|
351
351
|
# end
|
352
|
-
#
|
352
|
+
#
|
353
353
|
# class Authorship < ActiveRecord::Base
|
354
354
|
# belongs_to :author
|
355
355
|
# belongs_to :book
|
356
356
|
# end
|
357
|
-
#
|
357
|
+
#
|
358
358
|
# @author = Author.find :first
|
359
359
|
# @author.authorships.collect { |a| a.book } # selects all books that the author's authorships belong to.
|
360
360
|
# @author.books # selects all books by using the Authorship join model
|
361
|
-
#
|
361
|
+
#
|
362
362
|
# You can also go through a +has_many+ association on the join model:
|
363
|
-
#
|
363
|
+
#
|
364
364
|
# class Firm < ActiveRecord::Base
|
365
365
|
# has_many :clients
|
366
366
|
# has_many :invoices, :through => :clients
|
367
367
|
# end
|
368
|
-
#
|
368
|
+
#
|
369
369
|
# class Client < ActiveRecord::Base
|
370
370
|
# belongs_to :firm
|
371
371
|
# has_many :invoices
|
372
372
|
# end
|
373
|
-
#
|
373
|
+
#
|
374
374
|
# class Invoice < ActiveRecord::Base
|
375
375
|
# belongs_to :client
|
376
376
|
# end
|
@@ -380,36 +380,36 @@ module ActiveRecord
|
|
380
380
|
# @firm.invoices # selects all invoices by going through the Client join model.
|
381
381
|
#
|
382
382
|
# === Polymorphic Associations
|
383
|
-
#
|
384
|
-
# Polymorphic associations on models are not restricted on what types of models they can be associated with. Rather, they
|
383
|
+
#
|
384
|
+
# Polymorphic associations on models are not restricted on what types of models they can be associated with. Rather, they
|
385
385
|
# specify an interface that a +has_many+ association must adhere to.
|
386
|
-
#
|
386
|
+
#
|
387
387
|
# class Asset < ActiveRecord::Base
|
388
388
|
# belongs_to :attachable, :polymorphic => true
|
389
389
|
# end
|
390
|
-
#
|
390
|
+
#
|
391
391
|
# class Post < ActiveRecord::Base
|
392
392
|
# has_many :assets, :as => :attachable # The :as option specifies the polymorphic interface to use.
|
393
393
|
# end
|
394
394
|
#
|
395
395
|
# @asset.attachable = @post
|
396
|
-
#
|
396
|
+
#
|
397
397
|
# This works by using a type column in addition to a foreign key to specify the associated record. In the Asset example, you'd need
|
398
398
|
# an +attachable_id+ integer column and an +attachable_type+ string column.
|
399
399
|
#
|
400
400
|
# Using polymorphic associations in combination with single table inheritance (STI) is a little tricky. In order
|
401
|
-
# for the associations to work as expected, ensure that you store the base model for the STI models in the
|
401
|
+
# for the associations to work as expected, ensure that you store the base model for the STI models in the
|
402
402
|
# type column of the polymorphic association. To continue with the asset example above, suppose there are guest posts
|
403
403
|
# and member posts that use the posts table for STI. In this case, there must be a +type+ column in the posts table.
|
404
404
|
#
|
405
405
|
# class Asset < ActiveRecord::Base
|
406
406
|
# belongs_to :attachable, :polymorphic => true
|
407
|
-
#
|
407
|
+
#
|
408
408
|
# def attachable_type=(sType)
|
409
409
|
# super(sType.to_s.classify.constantize.base_class.to_s)
|
410
410
|
# end
|
411
411
|
# end
|
412
|
-
#
|
412
|
+
#
|
413
413
|
# class Post < ActiveRecord::Base
|
414
414
|
# # because we store "Post" in attachable_type now :dependent => :destroy will work
|
415
415
|
# has_many :assets, :as => :attachable, :dependent => :destroy
|
@@ -424,7 +424,7 @@ module ActiveRecord
|
|
424
424
|
# == Caching
|
425
425
|
#
|
426
426
|
# All of the methods are built on a simple caching principle that will keep the result of the last query around unless specifically
|
427
|
-
# instructed not to. The cache is even shared across methods to make it even cheaper to use the macro-added methods without
|
427
|
+
# instructed not to. The cache is even shared across methods to make it even cheaper to use the macro-added methods without
|
428
428
|
# worrying too much about performance at the first go. Example:
|
429
429
|
#
|
430
430
|
# project.milestones # fetches milestones from the database
|
@@ -450,7 +450,7 @@ module ActiveRecord
|
|
450
450
|
# puts "Post: " + post.title
|
451
451
|
# puts "Written by: " + post.author.name
|
452
452
|
# puts "Last comment on: " + post.comments.first.created_on
|
453
|
-
# end
|
453
|
+
# end
|
454
454
|
#
|
455
455
|
# To iterate over these one hundred posts, we'll generate 201 database queries. Let's first just optimize it for retrieving the author:
|
456
456
|
#
|
@@ -475,7 +475,7 @@ module ActiveRecord
|
|
475
475
|
# All of this power shouldn't fool you into thinking that you can pull out huge amounts of data with no performance penalty just because you've reduced
|
476
476
|
# the number of queries. The database still needs to send all the data to Active Record and it still needs to be processed. So it's no
|
477
477
|
# catch-all for performance problems, but it's a great way to cut down on the number of queries in a situation as the one described above.
|
478
|
-
#
|
478
|
+
#
|
479
479
|
# Since the eager loading pulls from multiple tables, you'll have to disambiguate any column references in both conditions and orders. So
|
480
480
|
# <tt>:order => "posts.id DESC"</tt> will work while <tt>:order => "id DESC"</tt> will not. Because eager loading generates the +SELECT+ statement too, the
|
481
481
|
# <tt>:select</tt> option is ignored.
|
@@ -483,37 +483,53 @@ module ActiveRecord
|
|
483
483
|
# You can use eager loading on multiple associations from the same table, but you cannot use those associations in orders and conditions
|
484
484
|
# as there is currently not any way to disambiguate them. Eager loading will not pull additional attributes on join tables, so "rich
|
485
485
|
# associations" with +has_and_belongs_to_many+ are not a good fit for eager loading.
|
486
|
-
#
|
486
|
+
#
|
487
487
|
# When eager loaded, conditions are interpolated in the context of the model class, not the model instance. Conditions are lazily interpolated
|
488
488
|
# before the actual model exists.
|
489
|
-
#
|
489
|
+
#
|
490
|
+
# Eager loading is not possible with polymorphic associations. Given
|
491
|
+
#
|
492
|
+
# class Address < ActiveRecord::Base
|
493
|
+
# belongs_to :addressable, :polymorphic => true
|
494
|
+
# end
|
495
|
+
#
|
496
|
+
# a call that tries to eager load the addressable model
|
497
|
+
#
|
498
|
+
# Address.find(:all, :include => :addressable) # INVALID
|
499
|
+
#
|
500
|
+
# will raise <tt>ActiveRecord::EagerLoadPolymorphicError</tt>. The reason is that the parent model's type
|
501
|
+
# is a column value so its corresponding table name cannot be put in the FROM/JOIN clauses of that early query.
|
502
|
+
#
|
503
|
+
# It does work the other way around though: if the <tt>User</tt> model is <tt>addressable</tt> you can eager load
|
504
|
+
# their addresses with <tt>:include</tt> just fine, every piece needed to construct the query is known beforehand.
|
505
|
+
#
|
490
506
|
# == Table Aliasing
|
491
507
|
#
|
492
508
|
# ActiveRecord uses table aliasing in the case that a table is referenced multiple times in a join. If a table is referenced only once,
|
493
509
|
# the standard table name is used. The second time, the table is aliased as <tt>#{reflection_name}_#{parent_table_name}</tt>. Indexes are appended
|
494
510
|
# for any more successive uses of the table name.
|
495
|
-
#
|
511
|
+
#
|
496
512
|
# Post.find :all, :include => :comments
|
497
513
|
# # => SELECT ... FROM posts LEFT OUTER JOIN comments ON ...
|
498
514
|
# Post.find :all, :include => :special_comments # STI
|
499
515
|
# # => SELECT ... FROM posts LEFT OUTER JOIN comments ON ... AND comments.type = 'SpecialComment'
|
500
516
|
# Post.find :all, :include => [:comments, :special_comments] # special_comments is the reflection name, posts is the parent table name
|
501
517
|
# # => SELECT ... FROM posts LEFT OUTER JOIN comments ON ... LEFT OUTER JOIN comments special_comments_posts
|
502
|
-
#
|
518
|
+
#
|
503
519
|
# Acts as tree example:
|
504
|
-
#
|
520
|
+
#
|
505
521
|
# TreeMixin.find :all, :include => :children
|
506
522
|
# # => SELECT ... FROM mixins LEFT OUTER JOIN mixins childrens_mixins ...
|
507
523
|
# TreeMixin.find :all, :include => {:children => :parent} # using cascading eager includes
|
508
|
-
# # => SELECT ... FROM mixins LEFT OUTER JOIN mixins childrens_mixins ...
|
524
|
+
# # => SELECT ... FROM mixins LEFT OUTER JOIN mixins childrens_mixins ...
|
525
|
+
# LEFT OUTER JOIN parents_mixins ...
|
526
|
+
# TreeMixin.find :all, :include => {:children => {:parent => :children}}
|
527
|
+
# # => SELECT ... FROM mixins LEFT OUTER JOIN mixins childrens_mixins ...
|
509
528
|
# LEFT OUTER JOIN parents_mixins ...
|
510
|
-
# TreeMixin.find :all, :include => {:children => {:parent => :children}}
|
511
|
-
# # => SELECT ... FROM mixins LEFT OUTER JOIN mixins childrens_mixins ...
|
512
|
-
# LEFT OUTER JOIN parents_mixins ...
|
513
529
|
# LEFT OUTER JOIN mixins childrens_mixins_2
|
514
|
-
#
|
530
|
+
#
|
515
531
|
# Has and Belongs to Many join tables use the same idea, but add a <tt>_join</tt> suffix:
|
516
|
-
#
|
532
|
+
#
|
517
533
|
# Post.find :all, :include => :categories
|
518
534
|
# # => SELECT ... FROM posts LEFT OUTER JOIN categories_posts ... LEFT OUTER JOIN categories ...
|
519
535
|
# Post.find :all, :include => {:categories => :posts}
|
@@ -523,18 +539,18 @@ module ActiveRecord
|
|
523
539
|
# # => SELECT ... FROM posts LEFT OUTER JOIN categories_posts ... LEFT OUTER JOIN categories ...
|
524
540
|
# LEFT OUTER JOIN categories_posts posts_categories_join LEFT OUTER JOIN posts posts_categories
|
525
541
|
# LEFT OUTER JOIN categories_posts categories_posts_join LEFT OUTER JOIN categories categories_posts
|
526
|
-
#
|
542
|
+
#
|
527
543
|
# If you wish to specify your own custom joins using a <tt>:joins</tt> option, those table names will take precedence over the eager associations:
|
528
|
-
#
|
544
|
+
#
|
529
545
|
# Post.find :all, :include => :comments, :joins => "inner join comments ..."
|
530
546
|
# # => SELECT ... FROM posts LEFT OUTER JOIN comments_posts ON ... INNER JOIN comments ...
|
531
547
|
# Post.find :all, :include => [:comments, :special_comments], :joins => "inner join comments ..."
|
532
|
-
# # => SELECT ... FROM posts LEFT OUTER JOIN comments comments_posts ON ...
|
548
|
+
# # => SELECT ... FROM posts LEFT OUTER JOIN comments comments_posts ON ...
|
533
549
|
# LEFT OUTER JOIN comments special_comments_posts ...
|
534
550
|
# INNER JOIN comments ...
|
535
|
-
#
|
551
|
+
#
|
536
552
|
# Table aliases are automatically truncated according to the maximum length of table identifiers according to the specific database.
|
537
|
-
#
|
553
|
+
#
|
538
554
|
# == Modules
|
539
555
|
#
|
540
556
|
# By default, associations will look for objects within the current module scope. Consider:
|
@@ -575,12 +591,12 @@ module ActiveRecord
|
|
575
591
|
# possible.
|
576
592
|
module ClassMethods
|
577
593
|
# Adds the following methods for retrieval and query of collections of associated objects:
|
578
|
-
# +collection+ is replaced with the symbol passed as the first argument, so
|
594
|
+
# +collection+ is replaced with the symbol passed as the first argument, so
|
579
595
|
# <tt>has_many :clients</tt> would add among others <tt>clients.empty?</tt>.
|
580
596
|
# * <tt>collection(force_reload = false)</tt> - returns an array of all the associated objects.
|
581
597
|
# An empty array is returned if none are found.
|
582
598
|
# * <tt>collection<<(object, ...)</tt> - adds one or more objects to the collection by setting their foreign keys to the collection's primary key.
|
583
|
-
# * <tt>collection.delete(object, ...)</tt> - removes one or more objects from the collection by setting their foreign keys to NULL.
|
599
|
+
# * <tt>collection.delete(object, ...)</tt> - removes one or more objects from the collection by setting their foreign keys to NULL.
|
584
600
|
# This will also destroy the objects if they're declared as +belongs_to+ and dependent on this model.
|
585
601
|
# * <tt>collection=objects</tt> - replaces the collections content by deleting and adding objects as appropriate.
|
586
602
|
# * <tt>collection_singular_ids</tt> - returns an array of the associated objects' ids
|
@@ -592,7 +608,7 @@ module ActiveRecord
|
|
592
608
|
# * <tt>collection.size</tt> - returns the number of associated objects.
|
593
609
|
# * <tt>collection.find</tt> - finds an associated object according to the same rules as Base.find.
|
594
610
|
# * <tt>collection.build(attributes = {}, ...)</tt> - returns one or more new objects of the collection type that have been instantiated
|
595
|
-
# with +attributes+ and linked to this object through a foreign key, but have not yet been saved. *Note:* This only works if an
|
611
|
+
# with +attributes+ and linked to this object through a foreign key, but have not yet been saved. *Note:* This only works if an
|
596
612
|
# associated object already exists, not if it's +nil+!
|
597
613
|
# * <tt>collection.create(attributes = {})</tt> - returns a new object of the collection type that has been instantiated
|
598
614
|
# with +attributes+, linked to this object through a foreign key, and that has already been saved (if it passed the validation).
|
@@ -612,7 +628,7 @@ module ActiveRecord
|
|
612
628
|
# * <tt>Firm#clients.build</tt> (similar to <tt>Client.new("firm_id" => id)</tt>)
|
613
629
|
# * <tt>Firm#clients.create</tt> (similar to <tt>c = Client.new("firm_id" => id); c.save; c</tt>)
|
614
630
|
# The declaration can also include an options hash to specialize the behavior of the association.
|
615
|
-
#
|
631
|
+
#
|
616
632
|
# Options are:
|
617
633
|
# * <tt>:class_name</tt> - specify the class name of the association. Use it only if that name can't be inferred
|
618
634
|
# from the association name. So <tt>has_many :products</tt> will by default be linked to the +Product+ class, but
|
@@ -637,13 +653,13 @@ module ActiveRecord
|
|
637
653
|
# * <tt>:group</tt>: An attribute name by which the result should be grouped. Uses the <tt>GROUP BY</tt> SQL-clause.
|
638
654
|
# * <tt>:limit</tt>: An integer determining the limit on the number of rows that should be returned.
|
639
655
|
# * <tt>:offset</tt>: An integer determining the offset from where the rows should be fetched. So at 5, it would skip the first 4 rows.
|
640
|
-
# * <tt>:select</tt>: By default, this is <tt>*</tt> as in <tt>SELECT * FROM</tt>, but can be changed if you, for example, want to do a join
|
656
|
+
# * <tt>:select</tt>: By default, this is <tt>*</tt> as in <tt>SELECT * FROM</tt>, but can be changed if you, for example, want to do a join
|
641
657
|
# but not include the joined columns.
|
642
658
|
# * <tt>:as</tt>: Specifies a polymorphic interface (See <tt>#belongs_to</tt>).
|
643
|
-
# * <tt>:through</tt>: Specifies a Join Model through which to perform the query. Options for <tt>:class_name</tt> and <tt>:foreign_key</tt>
|
659
|
+
# * <tt>:through</tt>: Specifies a Join Model through which to perform the query. Options for <tt>:class_name</tt> and <tt>:foreign_key</tt>
|
644
660
|
# are ignored, as the association uses the source reflection. You can only use a <tt>:through</tt> query through a <tt>belongs_to</tt>
|
645
661
|
# or <tt>has_many</tt> association on the join model.
|
646
|
-
# * <tt>:source</tt>: Specifies the source association name used by <tt>has_many :through</tt> queries. Only use it if the name cannot be
|
662
|
+
# * <tt>:source</tt>: Specifies the source association name used by <tt>has_many :through</tt> queries. Only use it if the name cannot be
|
647
663
|
# inferred from the association. <tt>has_many :subscribers, :through => :subscriptions</tt> will look for either <tt>:subscribers</tt> or
|
648
664
|
# <tt>:subscriber</tt> on +Subscription+, unless a <tt>:source</tt> is given.
|
649
665
|
# * <tt>:source_type</tt>: Specifies type of the source association used by <tt>has_many :through</tt> queries where the source
|
@@ -669,7 +685,6 @@ module ActiveRecord
|
|
669
685
|
configure_dependency_for_has_many(reflection)
|
670
686
|
|
671
687
|
if options[:through]
|
672
|
-
collection_reader_method(reflection, HasManyThroughAssociation)
|
673
688
|
collection_accessor_methods(reflection, HasManyThroughAssociation, false)
|
674
689
|
else
|
675
690
|
add_multiple_associated_save_callbacks(reflection.name)
|
@@ -679,10 +694,10 @@ module ActiveRecord
|
|
679
694
|
end
|
680
695
|
|
681
696
|
# Adds the following methods for retrieval and query of a single associated object:
|
682
|
-
# +association+ is replaced with the symbol passed as the first argument, so
|
697
|
+
# +association+ is replaced with the symbol passed as the first argument, so
|
683
698
|
# <tt>has_one :manager</tt> would add among others <tt>manager.nil?</tt>.
|
684
699
|
# * <tt>association(force_reload = false)</tt> - returns the associated object. +nil+ is returned if none is found.
|
685
|
-
# * <tt>association=(associate)</tt> - assigns the associate object, extracts the primary key, sets it as the foreign key,
|
700
|
+
# * <tt>association=(associate)</tt> - assigns the associate object, extracts the primary key, sets it as the foreign key,
|
686
701
|
# and saves the associate object.
|
687
702
|
# * <tt>association.nil?</tt> - returns +true+ if there is no associated object.
|
688
703
|
# * <tt>build_association(attributes = {})</tt> - returns a new object of the associated type that has been instantiated
|
@@ -699,7 +714,7 @@ module ActiveRecord
|
|
699
714
|
# * <tt>Account#create_beneficiary</tt> (similar to <tt>b = Beneficiary.new("account_id" => id); b.save; b</tt>)
|
700
715
|
#
|
701
716
|
# The declaration can also include an options hash to specialize the behavior of the association.
|
702
|
-
#
|
717
|
+
#
|
703
718
|
# Options are:
|
704
719
|
# * <tt>:class_name</tt> - specify the class name of the association. Use it only if that name can't be inferred
|
705
720
|
# from the association name. So <tt>has_one :manager</tt> will by default be linked to the +Manager+ class, but
|
@@ -726,25 +741,28 @@ module ActiveRecord
|
|
726
741
|
def has_one(association_id, options = {})
|
727
742
|
reflection = create_has_one_reflection(association_id, options)
|
728
743
|
|
744
|
+
ivar = "@#{reflection.name}"
|
745
|
+
|
729
746
|
module_eval do
|
730
747
|
after_save <<-EOF
|
731
|
-
association = instance_variable_get("
|
748
|
+
association = instance_variable_get("#{ivar}") if instance_variable_defined?("#{ivar}")
|
749
|
+
|
732
750
|
if !association.nil? && (new_record? || association.new_record? || association["#{reflection.primary_key_name}"] != id)
|
733
751
|
association["#{reflection.primary_key_name}"] = id
|
734
752
|
association.save(true)
|
735
753
|
end
|
736
754
|
EOF
|
737
755
|
end
|
738
|
-
|
756
|
+
|
739
757
|
association_accessor_methods(reflection, HasOneAssociation)
|
740
758
|
association_constructor_method(:build, reflection, HasOneAssociation)
|
741
759
|
association_constructor_method(:create, reflection, HasOneAssociation)
|
742
|
-
|
760
|
+
|
743
761
|
configure_dependency_for_has_one(reflection)
|
744
762
|
end
|
745
763
|
|
746
764
|
# Adds the following methods for retrieval and query for a single associated object for which this object holds an id:
|
747
|
-
# +association+ is replaced with the symbol passed as the first argument, so
|
765
|
+
# +association+ is replaced with the symbol passed as the first argument, so
|
748
766
|
# <tt>belongs_to :author</tt> would add among others <tt>author.nil?</tt>.
|
749
767
|
# * <tt>association(force_reload = false)</tt> - returns the associated object. +nil+ is returned if none is found.
|
750
768
|
# * <tt>association=(associate)</tt> - assigns the associate object, extracts the primary key, and sets it as the foreign key.
|
@@ -762,7 +780,7 @@ module ActiveRecord
|
|
762
780
|
# * <tt>Post#build_author</tt> (similar to <tt>post.author = Author.new</tt>)
|
763
781
|
# * <tt>Post#create_author</tt> (similar to <tt>post.author = Author.new; post.author.save; post.author</tt>)
|
764
782
|
# The declaration can also include an options hash to specialize the behavior of the association.
|
765
|
-
#
|
783
|
+
#
|
766
784
|
# Options are:
|
767
785
|
# * <tt>:class_name</tt> - specify the class name of the association. Use it only if that name can't be inferred
|
768
786
|
# from the association name. So <tt>has_one :author</tt> will by default be linked to the +Author+ class, but
|
@@ -772,39 +790,43 @@ module ActiveRecord
|
|
772
790
|
# * <tt>:order</tt> - specify the order in which the associated objects are returned as an <tt>ORDER BY</tt> SQL fragment,
|
773
791
|
# such as <tt>last_name, first_name DESC</tt>
|
774
792
|
# * <tt>:foreign_key</tt> - specify the foreign key used for the association. By default this is guessed to be the name
|
775
|
-
# of the
|
776
|
-
# +
|
777
|
-
# * <tt>:counter_cache</tt> - caches the number of belonging objects on the associate class through the use of +increment_counter+
|
793
|
+
# of the association with an +_id+ suffix. So a class that defines a +belongs_to :person+ association will use +person_id+ as the default +foreign_key+.
|
794
|
+
# Similarly, +belongs_to :favorite_person, :class_name => "Person"+ will use a foreign key of +favorite_person_id+.
|
795
|
+
# * <tt>:counter_cache</tt> - caches the number of belonging objects on the associate class through the use of +increment_counter+
|
778
796
|
# and +decrement_counter+. The counter cache is incremented when an object of this class is created and decremented when it's
|
779
797
|
# destroyed. This requires that a column named <tt>#{table_name}_count</tt> (such as +comments_count+ for a belonging +Comment+ class)
|
780
|
-
# is used on the associate class (such as a +Post+ class). You can also specify a custom counter cache column by providing
|
798
|
+
# is used on the associate class (such as a +Post+ class). You can also specify a custom counter cache column by providing
|
781
799
|
# a column name instead of a +true+/+false+ value to this option (e.g., <tt>:counter_cache => :my_custom_counter</tt>.)
|
782
800
|
# Note: Specifying a counter_cache will add it to that model's list of readonly attributes using #attr_readonly.
|
783
801
|
# * <tt>:include</tt> - specify second-order associations that should be eager loaded when this object is loaded.
|
802
|
+
# Not allowed if the association is polymorphic.
|
784
803
|
# * <tt>:polymorphic</tt> - specify this association is a polymorphic association by passing +true+.
|
785
|
-
# Note: If you've enabled the counter cache, then you may want to add the counter cache attribute
|
804
|
+
# Note: If you've enabled the counter cache, then you may want to add the counter cache attribute
|
786
805
|
# to the attr_readonly list in the associated classes (e.g. class Post; attr_readonly :comments_count; end).
|
787
806
|
#
|
788
807
|
# Option examples:
|
789
808
|
# belongs_to :firm, :foreign_key => "client_of"
|
790
809
|
# belongs_to :author, :class_name => "Person", :foreign_key => "author_id"
|
791
|
-
# belongs_to :valid_coupon, :class_name => "Coupon", :foreign_key => "coupon_id",
|
810
|
+
# belongs_to :valid_coupon, :class_name => "Coupon", :foreign_key => "coupon_id",
|
792
811
|
# :conditions => 'discounts > #{payments_count}'
|
793
812
|
# belongs_to :attachable, :polymorphic => true
|
794
813
|
def belongs_to(association_id, options = {})
|
795
814
|
reflection = create_belongs_to_reflection(association_id, options)
|
796
|
-
|
815
|
+
|
816
|
+
ivar = "@#{reflection.name}"
|
817
|
+
|
797
818
|
if reflection.options[:polymorphic]
|
798
819
|
association_accessor_methods(reflection, BelongsToPolymorphicAssociation)
|
799
820
|
|
800
821
|
module_eval do
|
801
822
|
before_save <<-EOF
|
802
|
-
association = instance_variable_get("
|
823
|
+
association = instance_variable_get("#{ivar}") if instance_variable_defined?("#{ivar}")
|
824
|
+
|
803
825
|
if association && association.target
|
804
826
|
if association.new_record?
|
805
827
|
association.save(true)
|
806
828
|
end
|
807
|
-
|
829
|
+
|
808
830
|
if association.updated?
|
809
831
|
self["#{reflection.primary_key_name}"] = association.id
|
810
832
|
self["#{reflection.options[:foreign_type]}"] = association.class.base_class.name.to_s
|
@@ -819,16 +841,17 @@ module ActiveRecord
|
|
819
841
|
|
820
842
|
module_eval do
|
821
843
|
before_save <<-EOF
|
822
|
-
association = instance_variable_get("
|
823
|
-
|
844
|
+
association = instance_variable_get("#{ivar}") if instance_variable_defined?("#{ivar}")
|
845
|
+
|
846
|
+
if !association.nil?
|
824
847
|
if association.new_record?
|
825
848
|
association.save(true)
|
826
849
|
end
|
827
|
-
|
850
|
+
|
828
851
|
if association.updated?
|
829
852
|
self["#{reflection.primary_key_name}"] = association.id
|
830
853
|
end
|
831
|
-
end
|
854
|
+
end
|
832
855
|
EOF
|
833
856
|
end
|
834
857
|
end
|
@@ -848,7 +871,7 @@ module ActiveRecord
|
|
848
871
|
"before_destroy '#{reflection.name}.class.decrement_counter(\"#{cache_column}\", #{reflection.primary_key_name})" +
|
849
872
|
" unless #{reflection.name}.nil?'"
|
850
873
|
)
|
851
|
-
|
874
|
+
|
852
875
|
module_eval(
|
853
876
|
"#{reflection.class_name}.send(:attr_readonly,\"#{cache_column}\".intern) if defined?(#{reflection.class_name}) && #{reflection.class_name}.respond_to?(:attr_readonly)"
|
854
877
|
)
|
@@ -858,11 +881,11 @@ module ActiveRecord
|
|
858
881
|
# Associates two classes via an intermediate join table. Unless the join table is explicitly specified as
|
859
882
|
# an option, it is guessed using the lexical order of the class names. So a join between +Developer+ and +Project+
|
860
883
|
# will give the default join table name of +developers_projects+ because "D" outranks "P". Note that this precedence
|
861
|
-
# is calculated using the <tt><</tt> operator for <tt>String</tt>. This means that if the strings are of different lengths,
|
884
|
+
# is calculated using the <tt><</tt> operator for <tt>String</tt>. This means that if the strings are of different lengths,
|
862
885
|
# and the strings are equal when compared up to the shortest length, then the longer string is considered of higher
|
863
|
-
# lexical precedence than the shorter one. For example, one would expect the tables <tt>paper_boxes</tt> and <tt>papers</tt>
|
886
|
+
# lexical precedence than the shorter one. For example, one would expect the tables <tt>paper_boxes</tt> and <tt>papers</tt>
|
864
887
|
# to generate a join table name of <tt>papers_paper_boxes</tt> because of the length of the name <tt>paper_boxes</tt>,
|
865
|
-
# but it in fact generates a join table name of <tt>paper_boxes_papers</tt>. Be aware of this caveat, and use the
|
888
|
+
# but it in fact generates a join table name of <tt>paper_boxes_papers</tt>. Be aware of this caveat, and use the
|
866
889
|
# custom <tt>join_table</tt> option if you need to.
|
867
890
|
#
|
868
891
|
# Deprecated: Any additional fields added to the join table will be placed as attributes when pulling records out through
|
@@ -871,13 +894,13 @@ module ActiveRecord
|
|
871
894
|
# associations with attributes to a real join model (see introduction).
|
872
895
|
#
|
873
896
|
# Adds the following methods for retrieval and query:
|
874
|
-
# +collection+ is replaced with the symbol passed as the first argument, so
|
897
|
+
# +collection+ is replaced with the symbol passed as the first argument, so
|
875
898
|
# <tt>has_and_belongs_to_many :categories</tt> would add among others <tt>categories.empty?</tt>.
|
876
899
|
# * <tt>collection(force_reload = false)</tt> - returns an array of all the associated objects.
|
877
900
|
# An empty array is returned if none are found.
|
878
|
-
# * <tt>collection<<(object, ...)</tt> - adds one or more objects to the collection by creating associations in the join table
|
901
|
+
# * <tt>collection<<(object, ...)</tt> - adds one or more objects to the collection by creating associations in the join table
|
879
902
|
# (<tt>collection.push</tt> and <tt>collection.concat</tt> are aliases to this method).
|
880
|
-
# * <tt>collection.delete(object, ...)</tt> - removes one or more objects from the collection by removing their associations from the join table.
|
903
|
+
# * <tt>collection.delete(object, ...)</tt> - removes one or more objects from the collection by removing their associations from the join table.
|
881
904
|
# This does not destroy the objects.
|
882
905
|
# * <tt>collection=objects</tt> - replaces the collection's content by deleting and adding objects as appropriate.
|
883
906
|
# * <tt>collection_singular_ids</tt> - returns an array of the associated objects' ids
|
@@ -906,10 +929,10 @@ module ActiveRecord
|
|
906
929
|
# * <tt>Developer#projects.build</tt> (similar to <tt>Project.new("project_id" => id)</tt>)
|
907
930
|
# * <tt>Developer#projects.create</tt> (similar to <tt>c = Project.new("project_id" => id); c.save; c</tt>)
|
908
931
|
# The declaration may include an options hash to specialize the behavior of the association.
|
909
|
-
#
|
932
|
+
#
|
910
933
|
# Options are:
|
911
934
|
# * <tt>:class_name</tt> - specify the class name of the association. Use it only if that name can't be inferred
|
912
|
-
# from the association name. So <tt>has_and_belongs_to_many :projects</tt> will by default be linked to the
|
935
|
+
# from the association name. So <tt>has_and_belongs_to_many :projects</tt> will by default be linked to the
|
913
936
|
# +Project+ class, but if the real class name is +SuperProject+, you'll have to specify it with this option.
|
914
937
|
# * <tt>:join_table</tt> - specify the name of the join table if the default based on lexical order isn't what you want.
|
915
938
|
# WARNING: If you're overwriting the table name of either class, the +table_name+ method MUST be declared underneath any
|
@@ -926,7 +949,7 @@ module ActiveRecord
|
|
926
949
|
# such as <tt>last_name, first_name DESC</tt>
|
927
950
|
# * <tt>:uniq</tt> - if set to +true+, duplicate associated objects will be ignored by accessors and query methods
|
928
951
|
# * <tt>:finder_sql</tt> - overwrite the default generated SQL statement used to fetch the association with a manual statement
|
929
|
-
# * <tt>:delete_sql</tt> - overwrite the default generated SQL statement used to remove links between the associated
|
952
|
+
# * <tt>:delete_sql</tt> - overwrite the default generated SQL statement used to remove links between the associated
|
930
953
|
# classes with a manual statement
|
931
954
|
# * <tt>:insert_sql</tt> - overwrite the default generated SQL statement used to add links between the associated classes
|
932
955
|
# with a manual statement
|
@@ -943,11 +966,11 @@ module ActiveRecord
|
|
943
966
|
# has_and_belongs_to_many :projects, :include => [ :milestones, :manager ]
|
944
967
|
# has_and_belongs_to_many :nations, :class_name => "Country"
|
945
968
|
# has_and_belongs_to_many :categories, :join_table => "prods_cats"
|
946
|
-
# has_and_belongs_to_many :active_projects, :join_table => 'developers_projects', :delete_sql =>
|
969
|
+
# has_and_belongs_to_many :active_projects, :join_table => 'developers_projects', :delete_sql =>
|
947
970
|
# 'DELETE FROM developers_projects WHERE active=1 AND developer_id = #{id} AND project_id = #{record.id}'
|
948
971
|
def has_and_belongs_to_many(association_id, options = {}, &extension)
|
949
972
|
reflection = create_has_and_belongs_to_many_reflection(association_id, options, &extension)
|
950
|
-
|
973
|
+
|
951
974
|
add_multiple_associated_save_callbacks(reflection.name)
|
952
975
|
collection_accessor_methods(reflection, HasAndBelongsToManyAssociation)
|
953
976
|
|
@@ -981,93 +1004,102 @@ module ActiveRecord
|
|
981
1004
|
|
982
1005
|
table_name_prefix + join_table + table_name_suffix
|
983
1006
|
end
|
984
|
-
|
1007
|
+
|
985
1008
|
def association_accessor_methods(reflection, association_proxy_class)
|
1009
|
+
ivar = "@#{reflection.name}"
|
1010
|
+
|
986
1011
|
define_method(reflection.name) do |*params|
|
987
1012
|
force_reload = params.first unless params.empty?
|
988
|
-
|
1013
|
+
|
1014
|
+
association = instance_variable_get(ivar) if instance_variable_defined?(ivar)
|
989
1015
|
|
990
1016
|
if association.nil? || force_reload
|
991
1017
|
association = association_proxy_class.new(self, reflection)
|
992
1018
|
retval = association.reload
|
993
1019
|
if retval.nil? and association_proxy_class == BelongsToAssociation
|
994
|
-
instance_variable_set(
|
1020
|
+
instance_variable_set(ivar, nil)
|
995
1021
|
return nil
|
996
1022
|
end
|
997
|
-
instance_variable_set(
|
1023
|
+
instance_variable_set(ivar, association)
|
998
1024
|
end
|
999
1025
|
|
1000
1026
|
association.target.nil? ? nil : association
|
1001
1027
|
end
|
1002
1028
|
|
1003
1029
|
define_method("#{reflection.name}=") do |new_value|
|
1004
|
-
association = instance_variable_get(
|
1030
|
+
association = instance_variable_get(ivar) if instance_variable_defined?(ivar)
|
1031
|
+
|
1005
1032
|
if association.nil? || association.target != new_value
|
1006
1033
|
association = association_proxy_class.new(self, reflection)
|
1007
1034
|
end
|
1008
1035
|
|
1009
1036
|
association.replace(new_value)
|
1010
1037
|
|
1011
|
-
|
1012
|
-
instance_variable_set("@#{reflection.name}", association)
|
1013
|
-
else
|
1014
|
-
instance_variable_set("@#{reflection.name}", nil)
|
1015
|
-
end
|
1038
|
+
instance_variable_set(ivar, new_value.nil? ? nil : association)
|
1016
1039
|
end
|
1017
1040
|
|
1018
1041
|
define_method("set_#{reflection.name}_target") do |target|
|
1019
1042
|
return if target.nil? and association_proxy_class == BelongsToAssociation
|
1020
1043
|
association = association_proxy_class.new(self, reflection)
|
1021
1044
|
association.target = target
|
1022
|
-
instance_variable_set(
|
1045
|
+
instance_variable_set(ivar, association)
|
1023
1046
|
end
|
1024
1047
|
end
|
1025
1048
|
|
1026
1049
|
def collection_reader_method(reflection, association_proxy_class)
|
1027
1050
|
define_method(reflection.name) do |*params|
|
1051
|
+
ivar = "@#{reflection.name}"
|
1052
|
+
|
1028
1053
|
force_reload = params.first unless params.empty?
|
1029
|
-
association = instance_variable_get(
|
1054
|
+
association = instance_variable_get(ivar) if instance_variable_defined?(ivar)
|
1030
1055
|
|
1031
1056
|
unless association.respond_to?(:loaded?)
|
1032
1057
|
association = association_proxy_class.new(self, reflection)
|
1033
|
-
instance_variable_set(
|
1058
|
+
instance_variable_set(ivar, association)
|
1034
1059
|
end
|
1035
1060
|
|
1036
1061
|
association.reload if force_reload
|
1037
1062
|
|
1038
1063
|
association
|
1039
1064
|
end
|
1065
|
+
|
1066
|
+
define_method("#{reflection.name.to_s.singularize}_ids") do
|
1067
|
+
send(reflection.name).map(&:id)
|
1068
|
+
end
|
1040
1069
|
end
|
1041
1070
|
|
1042
1071
|
def collection_accessor_methods(reflection, association_proxy_class, writer = true)
|
1043
1072
|
collection_reader_method(reflection, association_proxy_class)
|
1044
1073
|
|
1045
|
-
|
1046
|
-
#
|
1047
|
-
|
1048
|
-
|
1049
|
-
|
1050
|
-
|
1074
|
+
if writer
|
1075
|
+
define_method("#{reflection.name}=") do |new_value|
|
1076
|
+
# Loads proxy class instance (defined in collection_reader_method) if not already loaded
|
1077
|
+
association = send(reflection.name)
|
1078
|
+
association.replace(new_value)
|
1079
|
+
association
|
1080
|
+
end
|
1051
1081
|
|
1052
|
-
|
1053
|
-
|
1082
|
+
define_method("#{reflection.name.to_s.singularize}_ids=") do |new_value|
|
1083
|
+
ids = (new_value || []).reject { |nid| nid.blank? }
|
1084
|
+
send("#{reflection.name}=", reflection.class_name.constantize.find(ids))
|
1085
|
+
end
|
1054
1086
|
end
|
1055
|
-
|
1056
|
-
define_method("#{reflection.name.to_s.singularize}_ids=") do |new_value|
|
1057
|
-
ids = (new_value || []).reject { |nid| nid.blank? }
|
1058
|
-
send("#{reflection.name}=", reflection.class_name.constantize.find(ids))
|
1059
|
-
end if writer
|
1060
1087
|
end
|
1061
1088
|
|
1062
1089
|
def add_multiple_associated_save_callbacks(association_name)
|
1063
1090
|
method_name = "validate_associated_records_for_#{association_name}".to_sym
|
1091
|
+
ivar = "@#{association_name}"
|
1092
|
+
|
1064
1093
|
define_method(method_name) do
|
1065
|
-
association = instance_variable_get(
|
1094
|
+
association = instance_variable_get(ivar) if instance_variable_defined?(ivar)
|
1095
|
+
|
1066
1096
|
if association.respond_to?(:loaded?)
|
1067
1097
|
if new_record?
|
1068
1098
|
association
|
1069
|
-
|
1099
|
+
elsif association.loaded?
|
1070
1100
|
association.select { |record| record.new_record? }
|
1101
|
+
else
|
1102
|
+
association.target.select { |record| record.new_record? }
|
1071
1103
|
end.each do |record|
|
1072
1104
|
errors.add "#{association_name}" unless record.valid?
|
1073
1105
|
end
|
@@ -1078,18 +1110,20 @@ module ActiveRecord
|
|
1078
1110
|
before_save("@new_record_before_save = new_record?; true")
|
1079
1111
|
|
1080
1112
|
after_callback = <<-end_eval
|
1081
|
-
association = instance_variable_get("
|
1113
|
+
association = instance_variable_get("#{ivar}") if instance_variable_defined?("#{ivar}")
|
1082
1114
|
|
1083
1115
|
records_to_save = if @new_record_before_save
|
1084
1116
|
association
|
1085
1117
|
elsif association.respond_to?(:loaded?) && association.loaded?
|
1086
1118
|
association.select { |record| record.new_record? }
|
1119
|
+
elsif association.respond_to?(:loaded?) && !association.loaded?
|
1120
|
+
association.target.select { |record| record.new_record? }
|
1087
1121
|
else
|
1088
1122
|
[]
|
1089
1123
|
end
|
1090
1124
|
|
1091
1125
|
records_to_save.each { |record| association.send(:insert_record, record) } unless records_to_save.blank?
|
1092
|
-
|
1126
|
+
|
1093
1127
|
# reconstruct the SQL queries now that we know the owner's id
|
1094
1128
|
association.send(:construct_sql) if association.respond_to?(:construct_sql)
|
1095
1129
|
end_eval
|
@@ -1101,13 +1135,15 @@ module ActiveRecord
|
|
1101
1135
|
|
1102
1136
|
def association_constructor_method(constructor, reflection, association_proxy_class)
|
1103
1137
|
define_method("#{constructor}_#{reflection.name}") do |*params|
|
1138
|
+
ivar = "@#{reflection.name}"
|
1139
|
+
|
1104
1140
|
attributees = params.first unless params.empty?
|
1105
1141
|
replace_existing = params[1].nil? ? true : params[1]
|
1106
|
-
association = instance_variable_get(
|
1142
|
+
association = instance_variable_get(ivar) if instance_variable_defined?(ivar)
|
1107
1143
|
|
1108
1144
|
if association.nil?
|
1109
1145
|
association = association_proxy_class.new(self, reflection)
|
1110
|
-
instance_variable_set(
|
1146
|
+
instance_variable_set(ivar, association)
|
1111
1147
|
end
|
1112
1148
|
|
1113
1149
|
if association_proxy_class == HasOneAssociation
|
@@ -1117,7 +1153,7 @@ module ActiveRecord
|
|
1117
1153
|
end
|
1118
1154
|
end
|
1119
1155
|
end
|
1120
|
-
|
1156
|
+
|
1121
1157
|
def find_with_associations(options = {})
|
1122
1158
|
catch :invalid_query do
|
1123
1159
|
join_dependency = JoinDependency.new(self, merge_includes(scope(:find, :include), options[:include]), options[:joins])
|
@@ -1173,12 +1209,12 @@ module ActiveRecord
|
|
1173
1209
|
:select, :conditions, :include, :order, :group, :limit, :offset,
|
1174
1210
|
:as, :through, :source, :source_type,
|
1175
1211
|
:uniq,
|
1176
|
-
:finder_sql, :counter_sql,
|
1177
|
-
:before_add, :after_add, :before_remove, :after_remove,
|
1212
|
+
:finder_sql, :counter_sql,
|
1213
|
+
:before_add, :after_add, :before_remove, :after_remove,
|
1178
1214
|
:extend
|
1179
1215
|
)
|
1180
1216
|
|
1181
|
-
options[:extend] = create_extension_modules(association_id, extension, options[:extend])
|
1217
|
+
options[:extend] = create_extension_modules(association_id, extension, options[:extend])
|
1182
1218
|
|
1183
1219
|
create_reflection(:has_many, association_id, options, self)
|
1184
1220
|
end
|
@@ -1193,10 +1229,10 @@ module ActiveRecord
|
|
1193
1229
|
|
1194
1230
|
def create_belongs_to_reflection(association_id, options)
|
1195
1231
|
options.assert_valid_keys(
|
1196
|
-
:class_name, :foreign_key, :foreign_type, :remote, :conditions, :order, :include, :dependent,
|
1232
|
+
:class_name, :foreign_key, :foreign_type, :remote, :conditions, :order, :include, :dependent,
|
1197
1233
|
:counter_cache, :extend, :polymorphic
|
1198
1234
|
)
|
1199
|
-
|
1235
|
+
|
1200
1236
|
reflection = create_reflection(:belongs_to, association_id, options, self)
|
1201
1237
|
|
1202
1238
|
if options[:polymorphic]
|
@@ -1205,23 +1241,23 @@ module ActiveRecord
|
|
1205
1241
|
|
1206
1242
|
reflection
|
1207
1243
|
end
|
1208
|
-
|
1244
|
+
|
1209
1245
|
def create_has_and_belongs_to_many_reflection(association_id, options, &extension)
|
1210
1246
|
options.assert_valid_keys(
|
1211
|
-
:class_name, :table_name, :join_table, :foreign_key, :association_foreign_key,
|
1247
|
+
:class_name, :table_name, :join_table, :foreign_key, :association_foreign_key,
|
1212
1248
|
:select, :conditions, :include, :order, :group, :limit, :offset,
|
1213
|
-
:uniq,
|
1249
|
+
:uniq,
|
1214
1250
|
:finder_sql, :delete_sql, :insert_sql,
|
1215
|
-
:before_add, :after_add, :before_remove, :after_remove,
|
1251
|
+
:before_add, :after_add, :before_remove, :after_remove,
|
1216
1252
|
:extend
|
1217
1253
|
)
|
1218
1254
|
|
1219
|
-
options[:extend] = create_extension_modules(association_id, extension, options[:extend])
|
1255
|
+
options[:extend] = create_extension_modules(association_id, extension, options[:extend])
|
1220
1256
|
|
1221
1257
|
reflection = create_reflection(:has_and_belongs_to_many, association_id, options, self)
|
1222
1258
|
|
1223
1259
|
reflection.options[:join_table] ||= join_table_name(undecorated_table_name(self.to_s), undecorated_table_name(reflection.class_name))
|
1224
|
-
|
1260
|
+
|
1225
1261
|
reflection
|
1226
1262
|
end
|
1227
1263
|
|
@@ -1232,7 +1268,7 @@ module ActiveRecord
|
|
1232
1268
|
def guard_against_unlimitable_reflections(reflections, options)
|
1233
1269
|
if (options[:offset] || options[:limit]) && !using_limitable_reflections?(reflections)
|
1234
1270
|
raise(
|
1235
|
-
ConfigurationError,
|
1271
|
+
ConfigurationError,
|
1236
1272
|
"You can not use offset and limit together with has_many or has_and_belongs_to_many associations"
|
1237
1273
|
)
|
1238
1274
|
end
|
@@ -1249,7 +1285,7 @@ module ActiveRecord
|
|
1249
1285
|
scope = scope(:find)
|
1250
1286
|
sql = "SELECT #{column_aliases(join_dependency)} FROM #{(scope && scope[:from]) || options[:from] || quoted_table_name} "
|
1251
1287
|
sql << join_dependency.join_associations.collect{|join| join.association_join }.join
|
1252
|
-
|
1288
|
+
|
1253
1289
|
add_joins!(sql, options, scope)
|
1254
1290
|
add_conditions!(sql, options[:conditions], scope)
|
1255
1291
|
add_limited_ids_condition!(sql, options, join_dependency) if !using_limitable_reflections?(join_dependency.reflections) && ((scope && scope[:limit]) || options[:limit])
|
@@ -1258,10 +1294,10 @@ module ActiveRecord
|
|
1258
1294
|
add_order!(sql, options[:order], scope)
|
1259
1295
|
add_limit!(sql, options, scope) if using_limitable_reflections?(join_dependency.reflections)
|
1260
1296
|
add_lock!(sql, options, scope)
|
1261
|
-
|
1297
|
+
|
1262
1298
|
return sanitize_sql(sql)
|
1263
1299
|
end
|
1264
|
-
|
1300
|
+
|
1265
1301
|
def add_limited_ids_condition!(sql, options, join_dependency)
|
1266
1302
|
unless (id_list = select_limited_ids_list(options, join_dependency)).empty?
|
1267
1303
|
sql << "#{condition_word(sql)} #{connection.quote_table_name table_name}.#{primary_key} IN (#{id_list}) "
|
@@ -1324,7 +1360,7 @@ module ActiveRecord
|
|
1324
1360
|
condition_table_name != table_name
|
1325
1361
|
end
|
1326
1362
|
end
|
1327
|
-
|
1363
|
+
|
1328
1364
|
# Checks if the query order references a table other than the current model's table.
|
1329
1365
|
def include_eager_order?(options)
|
1330
1366
|
order = options[:order]
|
@@ -1362,13 +1398,16 @@ module ActiveRecord
|
|
1362
1398
|
end
|
1363
1399
|
|
1364
1400
|
def create_extension_modules(association_id, block_extension, extensions)
|
1365
|
-
|
1401
|
+
if block_extension
|
1402
|
+
extension_module_name = "#{self.to_s}#{association_id.to_s.camelize}AssociationExtension"
|
1366
1403
|
|
1367
|
-
|
1368
|
-
|
1404
|
+
silence_warnings do
|
1405
|
+
Object.const_set(extension_module_name, Module.new(&block_extension))
|
1406
|
+
end
|
1407
|
+
Array(extensions).push(extension_module_name.constantize)
|
1408
|
+
else
|
1409
|
+
Array(extensions)
|
1369
1410
|
end
|
1370
|
-
|
1371
|
-
Array(extensions).push(extension_module_name.constantize)
|
1372
1411
|
end
|
1373
1412
|
|
1374
1413
|
class JoinDependency # :nodoc:
|
@@ -1526,13 +1565,15 @@ module ActiveRecord
|
|
1526
1565
|
end
|
1527
1566
|
|
1528
1567
|
def column_names_with_alias
|
1529
|
-
unless @column_names_with_alias
|
1568
|
+
unless defined?(@column_names_with_alias)
|
1530
1569
|
@column_names_with_alias = []
|
1570
|
+
|
1531
1571
|
([primary_key] + (column_names - [primary_key])).each_with_index do |column_name, i|
|
1532
1572
|
@column_names_with_alias << [column_name, "#{ aliased_prefix }_r#{ i }"]
|
1533
1573
|
end
|
1534
1574
|
end
|
1535
|
-
|
1575
|
+
|
1576
|
+
@column_names_with_alias
|
1536
1577
|
end
|
1537
1578
|
|
1538
1579
|
def extract_record(row)
|
@@ -1568,7 +1609,7 @@ module ActiveRecord
|
|
1568
1609
|
if !parent.table_joins.blank? && parent.table_joins.to_s.downcase =~ %r{join(\s+\w+)?\s+#{aliased_table_name.downcase}\son}
|
1569
1610
|
join_dependency.table_aliases[aliased_table_name] += 1
|
1570
1611
|
end
|
1571
|
-
|
1612
|
+
|
1572
1613
|
unless join_dependency.table_aliases[aliased_table_name].zero?
|
1573
1614
|
# if the table name has been used, then use an alias
|
1574
1615
|
@aliased_table_name = active_record.connection.table_alias_for "#{pluralize(reflection.name)}_#{parent_table_name}"
|
@@ -1578,7 +1619,7 @@ module ActiveRecord
|
|
1578
1619
|
else
|
1579
1620
|
join_dependency.table_aliases[aliased_table_name] += 1
|
1580
1621
|
end
|
1581
|
-
|
1622
|
+
|
1582
1623
|
if reflection.macro == :has_and_belongs_to_many || (reflection.macro == :has_many && reflection.options[:through])
|
1583
1624
|
@aliased_join_table_name = reflection.macro == :has_and_belongs_to_many ? reflection.options[:join_table] : reflection.through_reflection.klass.table_name
|
1584
1625
|
unless join_dependency.table_aliases[aliased_join_table_name].zero?
|
@@ -1601,22 +1642,22 @@ module ActiveRecord
|
|
1601
1642
|
connection.quote_table_name(aliased_join_table_name),
|
1602
1643
|
options[:foreign_key] || reflection.active_record.to_s.foreign_key,
|
1603
1644
|
connection.quote_table_name(parent.aliased_table_name),
|
1604
|
-
|
1645
|
+
reflection.active_record.primary_key] +
|
1605
1646
|
" #{join_type} %s ON %s.%s = %s.%s " % [
|
1606
1647
|
table_name_and_alias,
|
1607
|
-
|
1608
|
-
|
1648
|
+
connection.quote_table_name(aliased_table_name),
|
1649
|
+
klass.primary_key,
|
1609
1650
|
connection.quote_table_name(aliased_join_table_name),
|
1610
|
-
|
1651
|
+
options[:association_foreign_key] || klass.to_s.foreign_key
|
1611
1652
|
]
|
1612
1653
|
when :has_many, :has_one
|
1613
1654
|
case
|
1614
1655
|
when reflection.macro == :has_many && reflection.options[:through]
|
1615
1656
|
through_conditions = through_reflection.options[:conditions] ? "AND #{interpolate_sql(sanitize_sql(through_reflection.options[:conditions]))}" : ''
|
1616
|
-
|
1617
|
-
jt_foreign_key = jt_as_extra = jt_source_extra = jt_sti_extra = nil
|
1618
|
-
first_key = second_key = as_extra = nil
|
1619
|
-
|
1657
|
+
|
1658
|
+
jt_foreign_key = jt_as_extra = jt_source_extra = jt_sti_extra = nil
|
1659
|
+
first_key = second_key = as_extra = nil
|
1660
|
+
|
1620
1661
|
if through_reflection.options[:as] # has_many :through against a polymorphic join
|
1621
1662
|
jt_foreign_key = through_reflection.options[:as].to_s + '_id'
|
1622
1663
|
jt_as_extra = " AND %s.%s = %s" % [
|
@@ -1625,24 +1666,24 @@ module ActiveRecord
|
|
1625
1666
|
klass.quote_value(parent.active_record.base_class.name)
|
1626
1667
|
]
|
1627
1668
|
else
|
1628
|
-
jt_foreign_key = through_reflection.primary_key_name
|
1669
|
+
jt_foreign_key = through_reflection.primary_key_name
|
1629
1670
|
end
|
1630
|
-
|
1671
|
+
|
1631
1672
|
case source_reflection.macro
|
1632
1673
|
when :has_many
|
1633
|
-
if source_reflection.options[:as]
|
1634
|
-
first_key = "#{source_reflection.options[:as]}_id"
|
1635
|
-
second_key = options[:foreign_key] || primary_key
|
1674
|
+
if source_reflection.options[:as]
|
1675
|
+
first_key = "#{source_reflection.options[:as]}_id"
|
1676
|
+
second_key = options[:foreign_key] || primary_key
|
1636
1677
|
as_extra = " AND %s.%s = %s" % [
|
1637
1678
|
connection.quote_table_name(aliased_table_name),
|
1638
1679
|
connection.quote_column_name("#{source_reflection.options[:as]}_type"),
|
1639
|
-
klass.quote_value(source_reflection.active_record.base_class.name)
|
1680
|
+
klass.quote_value(source_reflection.active_record.base_class.name)
|
1640
1681
|
]
|
1641
1682
|
else
|
1642
1683
|
first_key = through_reflection.klass.base_class.to_s.foreign_key
|
1643
1684
|
second_key = options[:foreign_key] || primary_key
|
1644
1685
|
end
|
1645
|
-
|
1686
|
+
|
1646
1687
|
unless through_reflection.klass.descends_from_active_record?
|
1647
1688
|
jt_sti_extra = " AND %s.%s = %s" % [
|
1648
1689
|
connection.quote_table_name(aliased_join_table_name),
|
@@ -1666,17 +1707,17 @@ module ActiveRecord
|
|
1666
1707
|
" #{join_type} %s ON (%s.%s = %s.%s%s%s%s) " % [
|
1667
1708
|
table_alias_for(through_reflection.klass.table_name, aliased_join_table_name),
|
1668
1709
|
connection.quote_table_name(parent.aliased_table_name),
|
1669
|
-
|
1710
|
+
connection.quote_column_name(parent.primary_key),
|
1670
1711
|
connection.quote_table_name(aliased_join_table_name),
|
1671
|
-
|
1712
|
+
connection.quote_column_name(jt_foreign_key),
|
1672
1713
|
jt_as_extra, jt_source_extra, jt_sti_extra
|
1673
1714
|
] +
|
1674
1715
|
" #{join_type} %s ON (%s.%s = %s.%s%s) " % [
|
1675
|
-
table_name_and_alias,
|
1716
|
+
table_name_and_alias,
|
1676
1717
|
connection.quote_table_name(aliased_table_name),
|
1677
|
-
|
1718
|
+
connection.quote_column_name(first_key),
|
1678
1719
|
connection.quote_table_name(aliased_join_table_name),
|
1679
|
-
|
1720
|
+
connection.quote_column_name(second_key),
|
1680
1721
|
as_extra
|
1681
1722
|
]
|
1682
1723
|
|
@@ -1684,11 +1725,11 @@ module ActiveRecord
|
|
1684
1725
|
" #{join_type} %s ON %s.%s = %s.%s AND %s.%s = %s" % [
|
1685
1726
|
table_name_and_alias,
|
1686
1727
|
connection.quote_table_name(aliased_table_name),
|
1687
|
-
|
1728
|
+
"#{reflection.options[:as]}_id",
|
1688
1729
|
connection.quote_table_name(parent.aliased_table_name),
|
1689
|
-
|
1730
|
+
parent.primary_key,
|
1690
1731
|
connection.quote_table_name(aliased_table_name),
|
1691
|
-
|
1732
|
+
"#{reflection.options[:as]}_type",
|
1692
1733
|
klass.quote_value(parent.active_record.base_class.name)
|
1693
1734
|
]
|
1694
1735
|
else
|
@@ -1696,18 +1737,18 @@ module ActiveRecord
|
|
1696
1737
|
" #{join_type} %s ON %s.%s = %s.%s " % [
|
1697
1738
|
table_name_and_alias,
|
1698
1739
|
aliased_table_name,
|
1699
|
-
|
1740
|
+
foreign_key,
|
1700
1741
|
parent.aliased_table_name,
|
1701
|
-
|
1742
|
+
parent.primary_key
|
1702
1743
|
]
|
1703
1744
|
end
|
1704
1745
|
when :belongs_to
|
1705
1746
|
" #{join_type} %s ON %s.%s = %s.%s " % [
|
1706
1747
|
table_name_and_alias,
|
1707
|
-
|
1708
|
-
|
1748
|
+
connection.quote_table_name(aliased_table_name),
|
1749
|
+
reflection.klass.primary_key,
|
1709
1750
|
connection.quote_table_name(parent.aliased_table_name),
|
1710
|
-
|
1751
|
+
options[:foreign_key] || reflection.primary_key_name
|
1711
1752
|
]
|
1712
1753
|
else
|
1713
1754
|
""
|
@@ -1723,15 +1764,14 @@ module ActiveRecord
|
|
1723
1764
|
|
1724
1765
|
join
|
1725
1766
|
end
|
1726
|
-
|
1727
|
-
protected
|
1728
1767
|
|
1768
|
+
protected
|
1729
1769
|
def pluralize(table_name)
|
1730
1770
|
ActiveRecord::Base.pluralize_table_names ? table_name.to_s.pluralize : table_name
|
1731
1771
|
end
|
1732
|
-
|
1772
|
+
|
1733
1773
|
def table_alias_for(table_name, table_alias)
|
1734
|
-
|
1774
|
+
"#{reflection.active_record.connection.quote_table_name(table_name)} #{table_alias if table_name != table_alias}".strip
|
1735
1775
|
end
|
1736
1776
|
|
1737
1777
|
def table_name_and_alias
|
@@ -1739,11 +1779,10 @@ module ActiveRecord
|
|
1739
1779
|
end
|
1740
1780
|
|
1741
1781
|
def interpolate_sql(sql)
|
1742
|
-
instance_eval("%@#{sql.gsub('@', '\@')}@")
|
1743
|
-
end
|
1782
|
+
instance_eval("%@#{sql.gsub('@', '\@')}@")
|
1783
|
+
end
|
1744
1784
|
|
1745
1785
|
private
|
1746
|
-
|
1747
1786
|
def join_type
|
1748
1787
|
"LEFT OUTER JOIN"
|
1749
1788
|
end
|