activerecord 3.1.11 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. data/CHANGELOG.md +6294 -97
  2. data/README.rdoc +2 -2
  3. data/examples/performance.rb +55 -31
  4. data/lib/active_record/aggregations.rb +2 -2
  5. data/lib/active_record/associations/association.rb +2 -42
  6. data/lib/active_record/associations/association_scope.rb +3 -30
  7. data/lib/active_record/associations/builder/association.rb +6 -4
  8. data/lib/active_record/associations/builder/belongs_to.rb +3 -3
  9. data/lib/active_record/associations/builder/collection_association.rb +2 -2
  10. data/lib/active_record/associations/builder/has_many.rb +4 -4
  11. data/lib/active_record/associations/builder/has_one.rb +5 -6
  12. data/lib/active_record/associations/builder/singular_association.rb +3 -16
  13. data/lib/active_record/associations/collection_association.rb +55 -28
  14. data/lib/active_record/associations/collection_proxy.rb +1 -35
  15. data/lib/active_record/associations/has_many_association.rb +5 -1
  16. data/lib/active_record/associations/has_many_through_association.rb +11 -8
  17. data/lib/active_record/associations/join_dependency.rb +1 -1
  18. data/lib/active_record/associations/preloader/association.rb +3 -1
  19. data/lib/active_record/associations.rb +82 -69
  20. data/lib/active_record/attribute_assignment.rb +221 -0
  21. data/lib/active_record/attribute_methods/deprecated_underscore_read.rb +32 -0
  22. data/lib/active_record/attribute_methods/dirty.rb +3 -3
  23. data/lib/active_record/attribute_methods/primary_key.rb +62 -25
  24. data/lib/active_record/attribute_methods/read.rb +72 -83
  25. data/lib/active_record/attribute_methods/serialization.rb +93 -0
  26. data/lib/active_record/attribute_methods/time_zone_conversion.rb +9 -14
  27. data/lib/active_record/attribute_methods/write.rb +27 -5
  28. data/lib/active_record/attribute_methods.rb +209 -30
  29. data/lib/active_record/autosave_association.rb +23 -8
  30. data/lib/active_record/base.rb +217 -1709
  31. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +98 -132
  32. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +82 -29
  33. data/lib/active_record/connection_adapters/abstract/database_statements.rb +13 -42
  34. data/lib/active_record/connection_adapters/abstract/query_cache.rb +1 -1
  35. data/lib/active_record/connection_adapters/abstract/quoting.rb +9 -12
  36. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +36 -25
  37. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +43 -22
  38. data/lib/active_record/connection_adapters/abstract_adapter.rb +78 -43
  39. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +653 -0
  40. data/lib/active_record/connection_adapters/column.rb +2 -2
  41. data/lib/active_record/connection_adapters/mysql2_adapter.rb +138 -578
  42. data/lib/active_record/connection_adapters/mysql_adapter.rb +86 -658
  43. data/lib/active_record/connection_adapters/postgresql_adapter.rb +144 -94
  44. data/lib/active_record/connection_adapters/schema_cache.rb +50 -0
  45. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +2 -6
  46. data/lib/active_record/connection_adapters/sqlite_adapter.rb +43 -22
  47. data/lib/active_record/counter_cache.rb +4 -3
  48. data/lib/active_record/dynamic_matchers.rb +79 -0
  49. data/lib/active_record/errors.rb +11 -1
  50. data/lib/active_record/explain.rb +83 -0
  51. data/lib/active_record/explain_subscriber.rb +21 -0
  52. data/lib/active_record/fixtures/file.rb +65 -0
  53. data/lib/active_record/fixtures.rb +31 -76
  54. data/lib/active_record/identity_map.rb +4 -11
  55. data/lib/active_record/inheritance.rb +167 -0
  56. data/lib/active_record/integration.rb +49 -0
  57. data/lib/active_record/locking/optimistic.rb +30 -25
  58. data/lib/active_record/locking/pessimistic.rb +23 -1
  59. data/lib/active_record/log_subscriber.rb +3 -3
  60. data/lib/active_record/migration/command_recorder.rb +8 -8
  61. data/lib/active_record/migration.rb +47 -30
  62. data/lib/active_record/model_schema.rb +366 -0
  63. data/lib/active_record/nested_attributes.rb +3 -2
  64. data/lib/active_record/persistence.rb +51 -9
  65. data/lib/active_record/querying.rb +58 -0
  66. data/lib/active_record/railtie.rb +24 -28
  67. data/lib/active_record/railties/controller_runtime.rb +3 -1
  68. data/lib/active_record/railties/databases.rake +134 -77
  69. data/lib/active_record/railties/jdbcmysql_error.rb +1 -1
  70. data/lib/active_record/readonly_attributes.rb +26 -0
  71. data/lib/active_record/reflection.rb +7 -15
  72. data/lib/active_record/relation/batches.rb +5 -2
  73. data/lib/active_record/relation/calculations.rb +27 -6
  74. data/lib/active_record/relation/delegation.rb +49 -0
  75. data/lib/active_record/relation/finder_methods.rb +6 -5
  76. data/lib/active_record/relation/predicate_builder.rb +12 -19
  77. data/lib/active_record/relation/query_methods.rb +76 -10
  78. data/lib/active_record/relation/spawn_methods.rb +11 -2
  79. data/lib/active_record/relation.rb +77 -34
  80. data/lib/active_record/result.rb +1 -1
  81. data/lib/active_record/sanitization.rb +194 -0
  82. data/lib/active_record/schema_dumper.rb +5 -2
  83. data/lib/active_record/scoping/default.rb +142 -0
  84. data/lib/active_record/scoping/named.rb +202 -0
  85. data/lib/active_record/scoping.rb +152 -0
  86. data/lib/active_record/serialization.rb +1 -43
  87. data/lib/active_record/serializers/xml_serializer.rb +2 -44
  88. data/lib/active_record/session_store.rb +15 -15
  89. data/lib/active_record/store.rb +50 -0
  90. data/lib/active_record/test_case.rb +11 -7
  91. data/lib/active_record/timestamp.rb +16 -3
  92. data/lib/active_record/transactions.rb +5 -5
  93. data/lib/active_record/translation.rb +22 -0
  94. data/lib/active_record/validations/associated.rb +5 -4
  95. data/lib/active_record/validations/uniqueness.rb +4 -4
  96. data/lib/active_record/validations.rb +1 -1
  97. data/lib/active_record/version.rb +2 -2
  98. data/lib/active_record.rb +28 -2
  99. data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -1
  100. data/lib/rails/generators/active_record/migration/templates/migration.rb +9 -3
  101. data/lib/rails/generators/active_record/model/model_generator.rb +5 -1
  102. data/lib/rails/generators/active_record/model/templates/migration.rb +3 -5
  103. data/lib/rails/generators/active_record/session_migration/templates/migration.rb +1 -5
  104. metadata +50 -40
  105. checksums.yaml +0 -7
  106. data/lib/active_record/named_scope.rb +0 -200
@@ -1,12 +1,5 @@
1
- require 'active_support/deprecation'
2
-
3
1
  module ActiveRecord
4
2
  module Associations
5
- AssociationCollection = ActiveSupport::Deprecation::DeprecatedConstantProxy.new(
6
- 'ActiveRecord::Associations::AssociationCollection',
7
- 'ActiveRecord::Associations::CollectionProxy'
8
- )
9
-
10
3
  # Association proxies in Active Record are middlemen between the object that
11
4
  # holds the association, known as the <tt>@owner</tt>, and the actual associated
12
5
  # object, known as the <tt>@target</tt>. The kind of association any proxy is
@@ -46,7 +39,7 @@ module ActiveRecord
46
39
  instance_methods.each { |m| undef_method m unless m.to_s =~ /^(?:nil\?|send|object_id|to_a)$|^__|^respond_to|proxy_/ }
47
40
 
48
41
  delegate :group, :order, :limit, :joins, :where, :preload, :eager_load, :includes, :from,
49
- :lock, :readonly, :having, :to => :scoped
42
+ :lock, :readonly, :having, :pluck, :to => :scoped
50
43
 
51
44
  delegate :target, :load_target, :loaded?, :to => :@association
52
45
 
@@ -134,33 +127,6 @@ module ActiveRecord
134
127
  proxy_association.reload
135
128
  self
136
129
  end
137
-
138
- def proxy_owner
139
- ActiveSupport::Deprecation.warn(
140
- "Calling record.#{@association.reflection.name}.proxy_owner is deprecated. Please use " \
141
- "record.association(:#{@association.reflection.name}).owner instead. Or, from an " \
142
- "association extension you can access proxy_association.owner."
143
- )
144
- proxy_association.owner
145
- end
146
-
147
- def proxy_target
148
- ActiveSupport::Deprecation.warn(
149
- "Calling record.#{@association.reflection.name}.proxy_target is deprecated. Please use " \
150
- "record.association(:#{@association.reflection.name}).target instead. Or, from an " \
151
- "association extension you can access proxy_association.target."
152
- )
153
- proxy_association.target
154
- end
155
-
156
- def proxy_reflection
157
- ActiveSupport::Deprecation.warn(
158
- "Calling record.#{@association.reflection.name}.proxy_reflection is deprecated. Please use " \
159
- "record.association(:#{@association.reflection.name}).reflection instead. Or, from an " \
160
- "association extension you can access proxy_association.reflection."
161
- )
162
- proxy_association.reflection
163
- end
164
130
  end
165
131
  end
166
132
  end
@@ -23,7 +23,7 @@ module ActiveRecord
23
23
  #
24
24
  # If the association has a counter cache it gets that value. Otherwise
25
25
  # it will attempt to do a count via SQL, bounded to <tt>:limit</tt> if
26
- # there's one. Some configuration options like :group make it impossible
26
+ # there's one. Some configuration options like :group make it impossible
27
27
  # to do an SQL count, in those cases the array count will be used.
28
28
  #
29
29
  # That does not depend on whether the collection has already been loaded
@@ -99,6 +99,10 @@ module ActiveRecord
99
99
  end
100
100
  end
101
101
  end
102
+
103
+ def foreign_key_present?
104
+ owner.attribute_present?(reflection.association_primary_key)
105
+ end
102
106
  end
103
107
  end
104
108
  end
@@ -8,7 +8,9 @@ module ActiveRecord
8
8
 
9
9
  def initialize(owner, reflection)
10
10
  super
11
- @through_records = {}
11
+
12
+ @through_records = {}
13
+ @through_association = nil
12
14
  end
13
15
 
14
16
  # Returns the size of the collection by executing a SELECT COUNT(*) query if the collection hasn't been
@@ -59,7 +61,7 @@ module ActiveRecord
59
61
  private
60
62
 
61
63
  def through_association
62
- owner.association(through_reflection.name)
64
+ @through_association ||= owner.association(through_reflection.name)
63
65
  end
64
66
 
65
67
  # We temporarily cache through record that has been build, because if we build a
@@ -122,8 +124,7 @@ module ActiveRecord
122
124
  def delete_records(records, method)
123
125
  ensure_not_nested
124
126
 
125
- through = through_association
126
- scope = through.scoped.where(construct_join_attributes(*records))
127
+ scope = through_association.scoped.where(construct_join_attributes(*records))
127
128
 
128
129
  case method
129
130
  when :destroy
@@ -134,7 +135,7 @@ module ActiveRecord
134
135
  count = scope.delete_all
135
136
  end
136
137
 
137
- delete_through_records(through, records)
138
+ delete_through_records(records)
138
139
 
139
140
  if through_reflection.macro == :has_many && update_through_counter?(method)
140
141
  update_counter(-count, through_reflection)
@@ -149,14 +150,16 @@ module ActiveRecord
149
150
  candidates.find_all { |c| c.attributes.slice(*attributes.keys) == attributes }
150
151
  end
151
152
 
152
- def delete_through_records(through, records)
153
+ def delete_through_records(records)
153
154
  records.each do |record|
154
155
  through_records = through_records_for(record)
155
156
 
156
157
  if through_reflection.macro == :has_many
157
- through_records.each { |r| through.target.delete(r) }
158
+ through_records.each { |r| through_association.target.delete(r) }
158
159
  else
159
- through.target = nil if through_records.include?(through.target)
160
+ if through_records.include?(through_association.target)
161
+ through_association.target = nil
162
+ end
160
163
  end
161
164
 
162
165
  @through_records.delete(record.object_id)
@@ -184,7 +184,7 @@ module ActiveRecord
184
184
 
185
185
  macro = join_part.reflection.macro
186
186
  if macro == :has_one
187
- return if record.association_cache.key?(join_part.reflection.name)
187
+ return record.association(join_part.reflection.name).target if record.association_cache.key?(join_part.reflection.name)
188
188
  association = join_part.instantiate(row) unless row[join_part.aliased_primary_key].nil?
189
189
  set_target_and_inverse(join_part, association, record)
190
190
  else
@@ -117,7 +117,9 @@ module ActiveRecord
117
117
  conditions = klass.send(:instance_eval, &conditions)
118
118
  end
119
119
 
120
- conditions
120
+ if conditions
121
+ klass.send(:sanitize_sql, conditions)
122
+ end
121
123
  end
122
124
  end
123
125
  end
@@ -5,7 +5,6 @@ require 'active_support/core_ext/object/blank'
5
5
  require 'active_support/core_ext/string/conversions'
6
6
  require 'active_support/core_ext/module/remove_method'
7
7
  require 'active_support/core_ext/class/attribute'
8
- require 'active_support/deprecation'
9
8
 
10
9
  module ActiveRecord
11
10
  class InverseOfAssociationNotFoundError < ActiveRecordError #:nodoc:
@@ -71,7 +70,7 @@ module ActiveRecord
71
70
  end
72
71
  end
73
72
 
74
- class HasManyThroughNestedAssociationsAreReadonly < ActiveRecordError #:nodoc
73
+ class HasManyThroughNestedAssociationsAreReadonly < ActiveRecordError #:nodoc:
75
74
  def initialize(owner, reflection)
76
75
  super("Cannot modify association '#{owner.class.name}##{reflection.name}' because it goes through more than one other association.")
77
76
  end
@@ -114,7 +113,6 @@ module ActiveRecord
114
113
  autoload :SingularAssociation, 'active_record/associations/singular_association'
115
114
  autoload :CollectionAssociation, 'active_record/associations/collection_association'
116
115
  autoload :CollectionProxy, 'active_record/associations/collection_proxy'
117
- autoload :AssociationCollection, 'active_record/associations/collection_proxy'
118
116
 
119
117
  autoload :BelongsToAssociation, 'active_record/associations/belongs_to_association'
120
118
  autoload :BelongsToPolymorphicAssociation, 'active_record/associations/belongs_to_polymorphic_association'
@@ -193,11 +191,31 @@ module ActiveRecord
193
191
  # * <tt>Project#portfolio, Project#portfolio=(portfolio), Project#portfolio.nil?</tt>
194
192
  # * <tt>Project#project_manager, Project#project_manager=(project_manager), Project#project_manager.nil?,</tt>
195
193
  # * <tt>Project#milestones.empty?, Project#milestones.size, Project#milestones, Project#milestones<<(milestone),</tt>
196
- # <tt>Project#milestones.delete(milestone), Project#milestones.find(milestone_id), Project#milestones.find(:all, options),</tt>
194
+ # <tt>Project#milestones.delete(milestone), Project#milestones.find(milestone_id), Project#milestones.all(options),</tt>
197
195
  # <tt>Project#milestones.build, Project#milestones.create</tt>
198
196
  # * <tt>Project#categories.empty?, Project#categories.size, Project#categories, Project#categories<<(category1),</tt>
199
197
  # <tt>Project#categories.delete(category1)</tt>
200
198
  #
199
+ # === Overriding generated methods
200
+ #
201
+ # Association methods are generated in a module that is included into the model class,
202
+ # which allows you to easily override with your own methods and call the original
203
+ # generated method with +super+. For example:
204
+ #
205
+ # class Car < ActiveRecord::Base
206
+ # belongs_to :owner
207
+ # belongs_to :old_owner
208
+ # def owner=(new_owner)
209
+ # self.old_owner = self.owner
210
+ # super
211
+ # end
212
+ # end
213
+ #
214
+ # If your model class is <tt>Project</tt>, the module is
215
+ # named <tt>Project::GeneratedFeatureMethods</tt>. The GeneratedFeatureMethods module is
216
+ # included in the model class immediately after the (anonymous) generated attributes methods
217
+ # module, meaning an association will override the methods for an attribute with the same name.
218
+ #
201
219
  # === A word of warning
202
220
  #
203
221
  # Don't create associations that have the same name as instance methods of
@@ -471,9 +489,9 @@ module ActiveRecord
471
489
  # === Association Join Models
472
490
  #
473
491
  # Has Many associations can be configured with the <tt>:through</tt> option to use an
474
- # explicit join model to retrieve the data. This operates similarly to a
475
- # +has_and_belongs_to_many+ association. The advantage is that you're able to add validations,
476
- # callbacks, and extra attributes on the join model. Consider the following schema:
492
+ # explicit join model to retrieve the data. This operates similarly to a
493
+ # +has_and_belongs_to_many+ association. The advantage is that you're able to add validations,
494
+ # callbacks, and extra attributes on the join model. Consider the following schema:
477
495
  #
478
496
  # class Author < ActiveRecord::Base
479
497
  # has_many :authorships
@@ -530,7 +548,7 @@ module ActiveRecord
530
548
  # @group.avatars # selects all avatars by going through the User join model.
531
549
  #
532
550
  # An important caveat with going through +has_one+ or +has_many+ associations on the
533
- # join model is that these associations are *read-only*. For example, the following
551
+ # join model is that these associations are *read-only*. For example, the following
534
552
  # would not work following the previous example:
535
553
  #
536
554
  # @group.avatars << Avatar.new # this would work if User belonged_to Avatar rather than the other way around
@@ -598,7 +616,7 @@ module ActiveRecord
598
616
  # === Polymorphic Associations
599
617
  #
600
618
  # Polymorphic associations on models are not restricted on what types of models they
601
- # can be associated with. Rather, they specify an interface that a +has_many+ association
619
+ # can be associated with. Rather, they specify an interface that a +has_many+ association
602
620
  # must adhere to.
603
621
  #
604
622
  # class Asset < ActiveRecord::Base
@@ -612,7 +630,7 @@ module ActiveRecord
612
630
  # @asset.attachable = @post
613
631
  #
614
632
  # This works by using a type column in addition to a foreign key to specify the associated
615
- # record. In the Asset example, you'd need an +attachable_id+ integer column and an
633
+ # record. In the Asset example, you'd need an +attachable_id+ integer column and an
616
634
  # +attachable_type+ string column.
617
635
  #
618
636
  # Using polymorphic associations in combination with single table inheritance (STI) is
@@ -668,7 +686,7 @@ module ActiveRecord
668
686
  #
669
687
  # Consider the following loop using the class above:
670
688
  #
671
- # for post in Post.all
689
+ # Post.all.each do |post|
672
690
  # puts "Post: " + post.title
673
691
  # puts "Written by: " + post.author.name
674
692
  # puts "Last comment on: " + post.comments.first.created_on
@@ -677,7 +695,7 @@ module ActiveRecord
677
695
  # To iterate over these one hundred posts, we'll generate 201 database queries. Let's
678
696
  # first just optimize it for retrieving the author:
679
697
  #
680
- # for post in Post.find(:all, :include => :author)
698
+ # Post.includes(:author).each do |post|
681
699
  #
682
700
  # This references the name of the +belongs_to+ association that also used the <tt>:author</tt>
683
701
  # symbol. After loading the posts, find will collect the +author_id+ from each one and load
@@ -686,7 +704,7 @@ module ActiveRecord
686
704
  #
687
705
  # We can improve upon the situation further by referencing both associations in the finder with:
688
706
  #
689
- # for post in Post.find(:all, :include => [ :author, :comments ])
707
+ # Post.includes(:author, :comments).each do |post|
690
708
  #
691
709
  # This will load all comments with a single query. This reduces the total number of queries
692
710
  # to 3. More generally the number of queries will be 1 plus the number of associations
@@ -694,7 +712,7 @@ module ActiveRecord
694
712
  #
695
713
  # To include a deep hierarchy of associations, use a hash:
696
714
  #
697
- # for post in Post.find(:all, :include => [ :author, { :comments => { :author => :gravatar } } ])
715
+ # Post.includes(:author, {:comments => {:author => :gravatar}}).each do |post|
698
716
  #
699
717
  # That'll grab not only all the comments but all their authors and gravatar pictures.
700
718
  # You can mix and match symbols, arrays and hashes in any combination to describe the
@@ -722,13 +740,13 @@ module ActiveRecord
722
740
  # <tt>:order => "author.name DESC"</tt> will work but <tt>:order => "name DESC"</tt> will not.
723
741
  #
724
742
  # If you do want eager load only some members of an association it is usually more natural
725
- # to <tt>:include</tt> an association which has conditions defined on it:
743
+ # to include an association which has conditions defined on it:
726
744
  #
727
745
  # class Post < ActiveRecord::Base
728
746
  # has_many :approved_comments, :class_name => 'Comment', :conditions => ['approved = ?', true]
729
747
  # end
730
748
  #
731
- # Post.find(:all, :include => :approved_comments)
749
+ # Post.includes(:approved_comments)
732
750
  #
733
751
  # This will load posts and eager load the +approved_comments+ association, which contains
734
752
  # only those comments that have been approved.
@@ -740,10 +758,10 @@ module ActiveRecord
740
758
  # has_many :most_recent_comments, :class_name => 'Comment', :order => 'id DESC', :limit => 10
741
759
  # end
742
760
  #
743
- # Picture.first(:include => :most_recent_comments).most_recent_comments # => returns all associated comments.
761
+ # Picture.includes(:most_recent_comments).first.most_recent_comments # => returns all associated comments.
744
762
  #
745
763
  # When eager loaded, conditions are interpolated in the context of the model class, not
746
- # the model instance. Conditions are lazily interpolated before the actual model exists.
764
+ # the model instance. Conditions are lazily interpolated before the actual model exists.
747
765
  #
748
766
  # Eager loading is supported with polymorphic associations.
749
767
  #
@@ -753,7 +771,7 @@ module ActiveRecord
753
771
  #
754
772
  # A call that tries to eager load the addressable model
755
773
  #
756
- # Address.find(:all, :include => :addressable)
774
+ # Address.includes(:addressable)
757
775
  #
758
776
  # This will execute one query to load the addresses and load the addressables with one
759
777
  # query per addressable type.
@@ -767,47 +785,47 @@ module ActiveRecord
767
785
  # == Table Aliasing
768
786
  #
769
787
  # Active Record uses table aliasing in the case that a table is referenced multiple times
770
- # in a join. If a table is referenced only once, the standard table name is used. The
788
+ # in a join. If a table is referenced only once, the standard table name is used. The
771
789
  # second time, the table is aliased as <tt>#{reflection_name}_#{parent_table_name}</tt>.
772
790
  # Indexes are appended for any more successive uses of the table name.
773
791
  #
774
- # Post.find :all, :joins => :comments
792
+ # Post.joins(:comments)
775
793
  # # => SELECT ... FROM posts INNER JOIN comments ON ...
776
- # Post.find :all, :joins => :special_comments # STI
794
+ # Post.joins(:special_comments) # STI
777
795
  # # => SELECT ... FROM posts INNER JOIN comments ON ... AND comments.type = 'SpecialComment'
778
- # Post.find :all, :joins => [:comments, :special_comments] # special_comments is the reflection name, posts is the parent table name
796
+ # Post.joins(:comments, :special_comments) # special_comments is the reflection name, posts is the parent table name
779
797
  # # => SELECT ... FROM posts INNER JOIN comments ON ... INNER JOIN comments special_comments_posts
780
798
  #
781
799
  # Acts as tree example:
782
800
  #
783
- # TreeMixin.find :all, :joins => :children
801
+ # TreeMixin.joins(:children)
784
802
  # # => SELECT ... FROM mixins INNER JOIN mixins childrens_mixins ...
785
- # TreeMixin.find :all, :joins => {:children => :parent}
803
+ # TreeMixin.joins(:children => :parent)
786
804
  # # => SELECT ... FROM mixins INNER JOIN mixins childrens_mixins ...
787
805
  # INNER JOIN parents_mixins ...
788
- # TreeMixin.find :all, :joins => {:children => {:parent => :children}}
806
+ # TreeMixin.joins(:children => {:parent => :children})
789
807
  # # => SELECT ... FROM mixins INNER JOIN mixins childrens_mixins ...
790
808
  # INNER JOIN parents_mixins ...
791
809
  # INNER JOIN mixins childrens_mixins_2
792
810
  #
793
811
  # Has and Belongs to Many join tables use the same idea, but add a <tt>_join</tt> suffix:
794
812
  #
795
- # Post.find :all, :joins => :categories
813
+ # Post.joins(:categories)
796
814
  # # => SELECT ... FROM posts INNER JOIN categories_posts ... INNER JOIN categories ...
797
- # Post.find :all, :joins => {:categories => :posts}
815
+ # Post.joins(:categories => :posts)
798
816
  # # => SELECT ... FROM posts INNER JOIN categories_posts ... INNER JOIN categories ...
799
817
  # INNER JOIN categories_posts posts_categories_join INNER JOIN posts posts_categories
800
- # Post.find :all, :joins => {:categories => {:posts => :categories}}
818
+ # Post.joins(:categories => {:posts => :categories})
801
819
  # # => SELECT ... FROM posts INNER JOIN categories_posts ... INNER JOIN categories ...
802
820
  # INNER JOIN categories_posts posts_categories_join INNER JOIN posts posts_categories
803
821
  # INNER JOIN categories_posts categories_posts_join INNER JOIN categories categories_posts_2
804
822
  #
805
- # If you wish to specify your own custom joins using a <tt>:joins</tt> option, those table
823
+ # If you wish to specify your own custom joins using <tt>joins</tt> method, those table
806
824
  # names will take precedence over the eager associations:
807
825
  #
808
- # Post.find :all, :joins => :comments, :joins => "inner join comments ..."
826
+ # Post.joins(:comments).joins("inner join comments ...")
809
827
  # # => SELECT ... FROM posts INNER JOIN comments_posts ON ... INNER JOIN comments ...
810
- # Post.find :all, :joins => [:comments, :special_comments], :joins => "inner join comments ..."
828
+ # Post.joins(:comments, :special_comments).joins("inner join comments ...")
811
829
  # # => SELECT ... FROM posts INNER JOIN comments comments_posts ON ...
812
830
  # INNER JOIN comments special_comments_posts ...
813
831
  # INNER JOIN comments ...
@@ -849,7 +867,7 @@ module ActiveRecord
849
867
  # == Bi-directional associations
850
868
  #
851
869
  # When you specify an association there is usually an association on the associated model
852
- # that specifies the same relationship in reverse. For example, with the following models:
870
+ # that specifies the same relationship in reverse. For example, with the following models:
853
871
  #
854
872
  # class Dungeon < ActiveRecord::Base
855
873
  # has_many :traps
@@ -866,9 +884,9 @@ module ActiveRecord
866
884
  #
867
885
  # The +traps+ association on +Dungeon+ and the +dungeon+ association on +Trap+ are
868
886
  # the inverse of each other and the inverse of the +dungeon+ association on +EvilWizard+
869
- # is the +evil_wizard+ association on +Dungeon+ (and vice-versa). By default,
887
+ # is the +evil_wizard+ association on +Dungeon+ (and vice-versa). By default,
870
888
  # Active Record doesn't know anything about these inverse relationships and so no object
871
- # loading optimisation is possible. For example:
889
+ # loading optimization is possible. For example:
872
890
  #
873
891
  # d = Dungeon.first
874
892
  # t = d.traps.first
@@ -878,8 +896,8 @@ module ActiveRecord
878
896
  #
879
897
  # The +Dungeon+ instances +d+ and <tt>t.dungeon</tt> in the above example refer to
880
898
  # the same object data from the database, but are actually different in-memory copies
881
- # of that data. Specifying the <tt>:inverse_of</tt> option on associations lets you tell
882
- # Active Record about inverse relationships and it will optimise object loading. For
899
+ # of that data. Specifying the <tt>:inverse_of</tt> option on associations lets you tell
900
+ # Active Record about inverse relationships and it will optimise object loading. For
883
901
  # example, if we changed our model definitions to:
884
902
  #
885
903
  # class Dungeon < ActiveRecord::Base
@@ -1039,7 +1057,7 @@ module ActiveRecord
1039
1057
  # === Example
1040
1058
  #
1041
1059
  # Example: A Firm class declares <tt>has_many :clients</tt>, which will add:
1042
- # * <tt>Firm#clients</tt> (similar to <tt>Clients.find :all, :conditions => ["firm_id = ?", id]</tt>)
1060
+ # * <tt>Firm#clients</tt> (similar to <tt>Clients.all :conditions => ["firm_id = ?", id]</tt>)
1043
1061
  # * <tt>Firm#clients<<</tt>
1044
1062
  # * <tt>Firm#clients.delete</tt>
1045
1063
  # * <tt>Firm#clients=</tt>
@@ -1062,7 +1080,7 @@ module ActiveRecord
1062
1080
  # specify it with this option.
1063
1081
  # [:conditions]
1064
1082
  # Specify the conditions that the associated objects must meet in order to be included as a +WHERE+
1065
- # SQL fragment, such as <tt>price > 5 AND name LIKE 'B%'</tt>. Record creations from
1083
+ # SQL fragment, such as <tt>price > 5 AND name LIKE 'B%'</tt>. Record creations from
1066
1084
  # the association are scoped if a hash is used.
1067
1085
  # <tt>has_many :posts, :conditions => {:published => true}</tt> will create published
1068
1086
  # posts with <tt>@blog.posts.create</tt> or <tt>@blog.posts.build</tt>.
@@ -1077,10 +1095,11 @@ module ActiveRecord
1077
1095
  # Specify the method that returns the primary key used for the association. By default this is +id+.
1078
1096
  # [:dependent]
1079
1097
  # If set to <tt>:destroy</tt> all the associated objects are destroyed
1080
- # alongside this object by calling their +destroy+ method. If set to <tt>:delete_all</tt> all associated
1081
- # objects are deleted *without* calling their +destroy+ method. If set to <tt>:nullify</tt> all associated
1098
+ # alongside this object by calling their +destroy+ method. If set to <tt>:delete_all</tt> all associated
1099
+ # objects are deleted *without* calling their +destroy+ method. If set to <tt>:nullify</tt> all associated
1082
1100
  # objects' foreign keys are set to +NULL+ *without* calling their +save+ callbacks. If set to
1083
- # <tt>:restrict</tt> this object cannot be deleted if it has any associated object.
1101
+ # <tt>:restrict</tt> this object raises an <tt>ActiveRecord::DeleteRestrictionError</tt> exception and
1102
+ # cannot be deleted if it has any associated objects.
1084
1103
  #
1085
1104
  # If using with the <tt>:through</tt> option, the association on the join model must be
1086
1105
  # a +belongs_to+, and the records which get deleted are the join records, rather than
@@ -1088,7 +1107,8 @@ module ActiveRecord
1088
1107
  #
1089
1108
  # [:finder_sql]
1090
1109
  # Specify a complete SQL statement to fetch the association. This is a good way to go for complex
1091
- # associations that depend on multiple tables. Note: When this option is used, +find_in_collection+
1110
+ # associations that depend on multiple tables. May be supplied as a string or a proc where interpolation is
1111
+ # required. Note: When this option is used, +find_in_collection+
1092
1112
  # is _not_ added.
1093
1113
  # [:counter_sql]
1094
1114
  # Specify a complete SQL statement to fetch the size of the association. If <tt>:finder_sql</tt> is
@@ -1163,11 +1183,14 @@ module ActiveRecord
1163
1183
  # has_many :tags, :as => :taggable
1164
1184
  # has_many :reports, :readonly => true
1165
1185
  # has_many :subscribers, :through => :subscriptions, :source => :user
1166
- # has_many :subscribers, :class_name => "Person", :finder_sql =>
1167
- # 'SELECT DISTINCT people.* ' +
1168
- # 'FROM people p, post_subscriptions ps ' +
1169
- # 'WHERE ps.post_id = #{id} AND ps.person_id = p.id ' +
1170
- # 'ORDER BY p.first_name'
1186
+ # has_many :subscribers, :class_name => "Person", :finder_sql => Proc.new {
1187
+ # %Q{
1188
+ # SELECT DISTINCT *
1189
+ # FROM people p, post_subscriptions ps
1190
+ # WHERE ps.post_id = #{id} AND ps.person_id = p.id
1191
+ # ORDER BY p.first_name
1192
+ # }
1193
+ # }
1171
1194
  def has_many(name, options = {}, &extension)
1172
1195
  Builder::HasMany.build(self, name, options, &extension)
1173
1196
  end
@@ -1229,7 +1252,8 @@ module ActiveRecord
1229
1252
  # If set to <tt>:destroy</tt>, the associated object is destroyed when this object is. If set to
1230
1253
  # <tt>:delete</tt>, the associated object is deleted *without* calling its destroy method.
1231
1254
  # If set to <tt>:nullify</tt>, the associated object's foreign key is set to +NULL+.
1232
- # Also, association is assigned.
1255
+ # Also, association is assigned. If set to <tt>:restrict</tt> this object raises an
1256
+ # <tt>ActiveRecord::DeleteRestrictionError</tt> exception and cannot be deleted if it has any associated object.
1233
1257
  # [:foreign_key]
1234
1258
  # Specify the foreign key used for the association. By default this is guessed to be the name
1235
1259
  # of this class in lower-case and "_id" suffixed. So a Person class that makes a +has_one+ association
@@ -1245,7 +1269,7 @@ module ActiveRecord
1245
1269
  # you want to do a join but not include the joined columns. Do not forget to include the
1246
1270
  # primary and foreign keys, otherwise it will raise an error.
1247
1271
  # [:through]
1248
- # Specifies a Join Model through which to perform the query. Options for <tt>:class_name</tt>,
1272
+ # Specifies a Join Model through which to perform the query. Options for <tt>:class_name</tt>,
1249
1273
  # <tt>:primary_key</tt>, and <tt>:foreign_key</tt> are ignored, as the association uses the
1250
1274
  # source reflection. You can only use a <tt>:through</tt> query through a <tt>has_one</tt>
1251
1275
  # or <tt>belongs_to</tt> association on the join model.
@@ -1267,7 +1291,7 @@ module ActiveRecord
1267
1291
  # By default, only save the associated object if it's a new record.
1268
1292
  # [:inverse_of]
1269
1293
  # Specifies the name of the <tt>belongs_to</tt> association on the associated object
1270
- # that is the inverse of this <tt>has_one</tt> association. Does not work in combination
1294
+ # that is the inverse of this <tt>has_one</tt> association. Does not work in combination
1271
1295
  # with <tt>:through</tt> or <tt>:as</tt> options.
1272
1296
  # See ActiveRecord::Associations::ClassMethods's overview on Bi-directional associations for more detail.
1273
1297
  #
@@ -1325,7 +1349,7 @@ module ActiveRecord
1325
1349
  #
1326
1350
  # [:class_name]
1327
1351
  # Specify the class name of the association. Use it only if that name can't be inferred
1328
- # from the association name. So <tt>has_one :author</tt> will by default be linked to the Author class, but
1352
+ # from the association name. So <tt>belongs_to :author</tt> will by default be linked to the Author class, but
1329
1353
  # if the real class name is Person, you'll have to specify it with this option.
1330
1354
  # [:conditions]
1331
1355
  # Specify the conditions that the associated object must meet in order to be included as a +WHERE+
@@ -1385,7 +1409,7 @@ module ActiveRecord
1385
1409
  # will be updated with the current time in addition to the updated_at/on attribute.
1386
1410
  # [:inverse_of]
1387
1411
  # Specifies the name of the <tt>has_one</tt> or <tt>has_many</tt> association on the associated
1388
- # object that is the inverse of this <tt>belongs_to</tt> association. Does not work in
1412
+ # object that is the inverse of this <tt>belongs_to</tt> association. Does not work in
1389
1413
  # combination with the <tt>:polymorphic</tt> options.
1390
1414
  # See ActiveRecord::Associations::ClassMethods's overview on Bi-directional associations for more detail.
1391
1415
  #
@@ -1405,15 +1429,15 @@ module ActiveRecord
1405
1429
  end
1406
1430
 
1407
1431
  # Specifies a many-to-many relationship with another class. This associates two classes via an
1408
- # intermediate join table. Unless the join table is explicitly specified as an option, it is
1432
+ # intermediate join table. Unless the join table is explicitly specified as an option, it is
1409
1433
  # guessed using the lexical order of the class names. So a join between Developer and Project
1410
1434
  # will give the default join table name of "developers_projects" because "D" outranks "P".
1411
- # Note that this precedence is calculated using the <tt><</tt> operator for String. This
1435
+ # Note that this precedence is calculated using the <tt><</tt> operator for String. This
1412
1436
  # means that if the strings are of different lengths, and the strings are equal when compared
1413
1437
  # up to the shortest length, then the longer string is considered of higher
1414
- # lexical precedence than the shorter one. For example, one would expect the tables "paper_boxes" and "papers"
1438
+ # lexical precedence than the shorter one. For example, one would expect the tables "paper_boxes" and "papers"
1415
1439
  # to generate a join table name of "papers_paper_boxes" because of the length of the name "paper_boxes",
1416
- # but it in fact generates a join table name of "paper_boxes_papers". Be aware of this caveat, and use the
1440
+ # but it in fact generates a join table name of "paper_boxes_papers". Be aware of this caveat, and use the
1417
1441
  # custom <tt>:join_table</tt> option if you need to.
1418
1442
  #
1419
1443
  # The join table should not have a primary key or a model associated with it. You must manually generate the
@@ -1515,7 +1539,7 @@ module ActiveRecord
1515
1539
  # the association will use "project_id" as the default <tt>:association_foreign_key</tt>.
1516
1540
  # [:conditions]
1517
1541
  # Specify the conditions that the associated object must meet in order to be included as a +WHERE+
1518
- # SQL fragment, such as <tt>authorized = 1</tt>. Record creations from the association are
1542
+ # SQL fragment, such as <tt>authorized = 1</tt>. Record creations from the association are
1519
1543
  # scoped if a hash is used.
1520
1544
  # <tt>has_many :posts, :conditions => {:published => true}</tt> will create published posts with <tt>@blog.posts.create</tt>
1521
1545
  # or <tt>@blog.posts.build</tt>.
@@ -1575,17 +1599,6 @@ module ActiveRecord
1575
1599
  def has_and_belongs_to_many(name, options = {}, &extension)
1576
1600
  Builder::HasAndBelongsToMany.build(self, name, options, &extension)
1577
1601
  end
1578
-
1579
- protected
1580
-
1581
- def preload_associations(records, associations, options = {}) #:nodoc:
1582
- ActiveSupport::Deprecation.warn(
1583
- "preload_associations(records, associations, options = {}) is deprecated. Use " \
1584
- "ActiveRecord::Associations::Preloader.new(records, associations, options = {}).run " \
1585
- "instead."
1586
- )
1587
- Preloader.new(records, associations, options).run
1588
- end
1589
1602
  end
1590
1603
  end
1591
1604
  end