activerecord 3.0.0.rc → 3.0.0.rc2

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.

Files changed (55) hide show
  1. data/CHANGELOG +6 -1
  2. data/README.rdoc +9 -9
  3. data/lib/active_record/aggregations.rb +64 -51
  4. data/lib/active_record/association_preload.rb +11 -9
  5. data/lib/active_record/associations.rb +300 -204
  6. data/lib/active_record/associations/association_collection.rb +7 -2
  7. data/lib/active_record/associations/belongs_to_association.rb +9 -5
  8. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +7 -6
  9. data/lib/active_record/associations/has_many_association.rb +6 -6
  10. data/lib/active_record/associations/has_many_through_association.rb +4 -3
  11. data/lib/active_record/associations/has_one_association.rb +7 -7
  12. data/lib/active_record/attribute_methods/time_zone_conversion.rb +2 -1
  13. data/lib/active_record/attribute_methods/write.rb +2 -2
  14. data/lib/active_record/autosave_association.rb +54 -72
  15. data/lib/active_record/base.rb +167 -108
  16. data/lib/active_record/callbacks.rb +43 -35
  17. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +8 -11
  18. data/lib/active_record/connection_adapters/abstract/database_limits.rb +1 -1
  19. data/lib/active_record/connection_adapters/abstract/query_cache.rb +0 -8
  20. data/lib/active_record/connection_adapters/abstract/quoting.rb +1 -1
  21. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +8 -6
  22. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +5 -3
  23. data/lib/active_record/connection_adapters/mysql_adapter.rb +5 -1
  24. data/lib/active_record/connection_adapters/postgresql_adapter.rb +9 -5
  25. data/lib/active_record/connection_adapters/sqlite_adapter.rb +5 -5
  26. data/lib/active_record/dynamic_finder_match.rb +3 -3
  27. data/lib/active_record/dynamic_scope_match.rb +1 -1
  28. data/lib/active_record/errors.rb +9 -5
  29. data/lib/active_record/fixtures.rb +36 -22
  30. data/lib/active_record/locale/en.yml +2 -2
  31. data/lib/active_record/migration.rb +36 -36
  32. data/lib/active_record/named_scope.rb +23 -11
  33. data/lib/active_record/nested_attributes.rb +3 -3
  34. data/lib/active_record/observer.rb +3 -3
  35. data/lib/active_record/persistence.rb +44 -29
  36. data/lib/active_record/railtie.rb +5 -8
  37. data/lib/active_record/railties/databases.rake +1 -1
  38. data/lib/active_record/reflection.rb +52 -52
  39. data/lib/active_record/relation.rb +26 -19
  40. data/lib/active_record/relation/batches.rb +4 -4
  41. data/lib/active_record/relation/calculations.rb +58 -34
  42. data/lib/active_record/relation/finder_methods.rb +21 -12
  43. data/lib/active_record/relation/query_methods.rb +26 -31
  44. data/lib/active_record/relation/spawn_methods.rb +17 -5
  45. data/lib/active_record/schema.rb +1 -1
  46. data/lib/active_record/schema_dumper.rb +12 -12
  47. data/lib/active_record/serialization.rb +1 -1
  48. data/lib/active_record/serializers/xml_serializer.rb +1 -1
  49. data/lib/active_record/session_store.rb +9 -9
  50. data/lib/active_record/test_case.rb +2 -2
  51. data/lib/active_record/timestamp.rb +31 -32
  52. data/lib/active_record/validations/associated.rb +4 -3
  53. data/lib/active_record/validations/uniqueness.rb +15 -11
  54. data/lib/active_record/version.rb +1 -1
  55. metadata +17 -16
@@ -422,7 +422,7 @@ module ActiveRecord
422
422
  match = DynamicFinderMatch.match(method)
423
423
  if match && match.creator?
424
424
  attributes = match.attribute_names
425
- return send(:"find_by_#{attributes.join('and')}", *args) || create(Hash[attributes.zip(args)])
425
+ return send(:"find_by_#{attributes.join('_and_')}", *args) || create(Hash[attributes.zip(args)])
426
426
  end
427
427
 
428
428
  if @target.respond_to?(method) || (!@reflection.klass.respond_to?(method) && Class.respond_to?(method))
@@ -492,7 +492,12 @@ module ActiveRecord
492
492
  def create_record(attrs)
493
493
  attrs.update(@reflection.options[:conditions]) if @reflection.options[:conditions].is_a?(Hash)
494
494
  ensure_owner_is_not_new
495
- record = @reflection.klass.send(:with_scope, :create => construct_scope[:create]) do
495
+
496
+ _scope = self.construct_scope[:create]
497
+ csm = @reflection.klass.send(:current_scoped_methods)
498
+ options = (csm.blank? || !_scope.is_a?(Hash)) ? _scope : _scope.merge(csm.where_values_hash)
499
+
500
+ record = @reflection.klass.send(:with_scope, :create => options) do
496
501
  @reflection.build_association(attrs)
497
502
  end
498
503
  if block_given?
@@ -22,7 +22,7 @@ module ActiveRecord
22
22
  else
23
23
  raise_on_type_mismatch(record)
24
24
 
25
- if counter_cache_name && !@owner.new_record?
25
+ if counter_cache_name && !@owner.new_record? && record.id != @owner[@reflection.primary_key_name]
26
26
  @reflection.klass.increment_counter(counter_cache_name, record.id)
27
27
  @reflection.klass.decrement_counter(counter_cache_name, @owner[@reflection.primary_key_name]) if @owner[@reflection.primary_key_name]
28
28
  end
@@ -49,12 +49,16 @@ module ActiveRecord
49
49
  else
50
50
  "find"
51
51
  end
52
+
53
+ options = @reflection.options.dup
54
+ (options.keys - [:select, :include, :readonly]).each do |key|
55
+ options.delete key
56
+ end
57
+ options[:conditions] = conditions
58
+
52
59
  the_target = @reflection.klass.send(find_method,
53
60
  @owner[@reflection.primary_key_name],
54
- :select => @reflection.options[:select],
55
- :conditions => conditions,
56
- :include => @reflection.options[:include],
57
- :readonly => @reflection.options[:readonly]
61
+ options
58
62
  ) if @owner[@reflection.primary_key_name]
59
63
  set_inverse_instance(the_target, @owner)
60
64
  the_target
@@ -24,7 +24,7 @@ module ActiveRecord
24
24
 
25
25
  protected
26
26
  def construct_find_options!(options)
27
- options[:joins] = @join_sql
27
+ options[:joins] = Arel::SqlLiteral.new @join_sql
28
28
  options[:readonly] = finding_with_ambiguous_select?(options[:select] || @reflection.options[:select])
29
29
  options[:select] ||= (@reflection.options[:select] || '*')
30
30
  end
@@ -79,7 +79,7 @@ module ActiveRecord
79
79
  else
80
80
  relation = Arel::Table.new(@reflection.options[:join_table])
81
81
  relation.where(relation[@reflection.primary_key_name].eq(@owner.id).
82
- and(Arel::Predicates::In.new(relation[@reflection.association_foreign_key], records.map(&:id)))
82
+ and(relation[@reflection.association_foreign_key].in(records.map { |x| x.id }))
83
83
  ).delete
84
84
  end
85
85
  end
@@ -106,9 +106,10 @@ module ActiveRecord
106
106
  :limit => @reflection.options[:limit] } }
107
107
  end
108
108
 
109
- # Join tables with additional columns on top of the two foreign keys must be considered ambiguous unless a select
110
- # clause has been explicitly defined. Otherwise you can get broken records back, if, for example, the join column also has
111
- # an id column. This will then overwrite the id column of the records coming back.
109
+ # Join tables with additional columns on top of the two foreign keys must be considered
110
+ # ambiguous unless a select clause has been explicitly defined. Otherwise you can get
111
+ # broken records back, if, for example, the join column also has an id column. This will
112
+ # then overwrite the id column of the records coming back.
112
113
  def finding_with_ambiguous_select?(select_clause)
113
114
  !select_clause && columns.size != 2
114
115
  end
@@ -126,7 +127,7 @@ module ActiveRecord
126
127
 
127
128
  def record_timestamp_columns(record)
128
129
  if record.record_timestamps
129
- record.send(:all_timestamp_attributes).map(&:to_s)
130
+ record.send(:all_timestamp_attributes).map { |x| x.to_s }
130
131
  else
131
132
  []
132
133
  end
@@ -24,7 +24,7 @@ module ActiveRecord
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
26
  # there's one. Some configuration options like :group make it impossible
27
- # to do a SQL count, in those cases the array count will be used.
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
30
30
  # or not. The +size+ method is the one that takes the loaded flag into
@@ -76,7 +76,7 @@ module ActiveRecord
76
76
  else
77
77
  relation = Arel::Table.new(@reflection.table_name)
78
78
  relation.where(relation[@reflection.primary_key_name].eq(@owner.id).
79
- and(Arel::Predicates::In.new(relation[@reflection.klass.primary_key], records.map(&:id)))
79
+ and(relation[@reflection.klass.primary_key].in(records.map { |r| r.id }))
80
80
  ).update(relation[@reflection.primary_key_name] => nil)
81
81
 
82
82
  @owner.class.update_counters(@owner.id, cached_counter_attribute_name => -records.size) if has_cached_counter?
@@ -110,10 +110,10 @@ module ActiveRecord
110
110
  create_scoping = {}
111
111
  set_belongs_to_association_for(create_scoping)
112
112
  {
113
- :find => { :conditions => @finder_sql,
114
- :readonly => false,
115
- :order => @reflection.options[:order],
116
- :limit => @reflection.options[:limit],
113
+ :find => { :conditions => @finder_sql,
114
+ :readonly => false,
115
+ :order => @reflection.options[:order],
116
+ :limit => @reflection.options[:limit],
117
117
  :include => @reflection.options[:include]},
118
118
  :create => create_scoping
119
119
  }
@@ -24,9 +24,10 @@ module ActiveRecord
24
24
  end
25
25
  end
26
26
 
27
- # Returns the size of the collection by executing a SELECT COUNT(*) query if the collection hasn't been loaded and
28
- # calling collection.size if it has. If it's more likely than not that the collection does have a size larger than zero,
29
- # and you need to fetch that collection afterwards, it'll take one fewer SELECT query if you use #length.
27
+ # Returns the size of the collection by executing a SELECT COUNT(*) query if the collection hasn't been
28
+ # loaded and calling collection.size if it has. If it's more likely than not that the collection does
29
+ # have a size larger than zero, and you need to fetch that collection afterwards, it'll take one fewer
30
+ # SELECT query if you use #length.
30
31
  def size
31
32
  return @owner.send(:read_attribute, cached_counter_attribute_name) if has_cached_counter?
32
33
  return @target.size if loaded?
@@ -79,13 +79,13 @@ module ActiveRecord
79
79
 
80
80
  private
81
81
  def find_target
82
- the_target = @reflection.klass.find(:first,
83
- :conditions => @finder_sql,
84
- :select => @reflection.options[:select],
85
- :order => @reflection.options[:order],
86
- :include => @reflection.options[:include],
87
- :readonly => @reflection.options[:readonly]
88
- )
82
+ options = @reflection.options.dup
83
+ (options.keys - [:select, :order, :include, :readonly]).each do |key|
84
+ options.delete key
85
+ end
86
+ options[:conditions] = @finder_sql
87
+
88
+ the_target = @reflection.klass.find(:first, options)
89
89
  set_inverse_instance(the_target, @owner)
90
90
  the_target
91
91
  end
@@ -14,7 +14,8 @@ module ActiveRecord
14
14
  module ClassMethods
15
15
  protected
16
16
  # Defined for all +datetime+ and +timestamp+ attributes when +time_zone_aware_attributes+ are enabled.
17
- # This enhanced read method automatically converts the UTC time stored in the database to the time zone stored in Time.zone.
17
+ # This enhanced read method automatically converts the UTC time stored in the database to the time
18
+ # zone stored in Time.zone.
18
19
  def define_method_attribute(attr_name)
19
20
  if create_time_zone_conversion_attribute?(attr_name, columns_hash[attr_name])
20
21
  method_body, line = <<-EOV, __LINE__ + 1
@@ -14,8 +14,8 @@ module ActiveRecord
14
14
  end
15
15
  end
16
16
 
17
- # Updates the attribute identified by <tt>attr_name</tt> with the specified +value+. Empty strings for fixnum and float
18
- # columns are turned into +nil+.
17
+ # Updates the attribute identified by <tt>attr_name</tt> with the specified +value+. Empty strings
18
+ # for fixnum and float columns are turned into +nil+.
19
19
  def write_attribute(attr_name, value)
20
20
  attr_name = attr_name.to_s
21
21
  attr_name = self.class.primary_key if attr_name == 'id'
@@ -2,16 +2,15 @@ require 'active_support/core_ext/array/wrap'
2
2
 
3
3
  module ActiveRecord
4
4
  # = Active Record Autosave Association
5
- #
6
- # AutosaveAssociation is a module that takes care of automatically saving
7
- # your associations when the parent is saved. In addition to saving, it
8
- # also destroys any associations that were marked for destruction.
9
- # (See mark_for_destruction and marked_for_destruction?)
5
+ #
6
+ # +AutosaveAssociation+ is a module that takes care of automatically saving
7
+ # associacted records when their parent is saved. In addition to saving, it
8
+ # also destroys any associated records that were marked for destruction.
9
+ # (See +mark_for_destruction+ and <tt>marked_for_destruction?</tt>).
10
10
  #
11
11
  # Saving of the parent, its associations, and the destruction of marked
12
- # associations, all happen inside 1 transaction. This should never leave the
13
- # database in an inconsistent state after, for instance, mass assigning
14
- # attributes and saving them.
12
+ # associations, all happen inside a transaction. This should never leave the
13
+ # database in an inconsistent state.
15
14
  #
16
15
  # If validations for any of the associations fail, their error messages will
17
16
  # be applied to the parent.
@@ -19,9 +18,10 @@ module ActiveRecord
19
18
  # Note that it also means that associations marked for destruction won't
20
19
  # be destroyed directly. They will however still be marked for destruction.
21
20
  #
22
- # === One-to-one Example
21
+ # Note that <tt>:autosave => false</tt> is not same as not declaring <tt>:autosave</tt>.
22
+ # When the <tt>:autosave</tt> option is not present new associations are saved.
23
23
  #
24
- # Consider a Post model with one Author:
24
+ # === One-to-one Example
25
25
  #
26
26
  # class Post
27
27
  # has_one :author, :autosave => true
@@ -31,7 +31,7 @@ module ActiveRecord
31
31
  # automatically _and_ atomically:
32
32
  #
33
33
  # post = Post.find(1)
34
- # post.title # => "The current global position of migrating ducks"
34
+ # post.title # => "The current global position of migrating ducks"
35
35
  # post.author.name # => "alloy"
36
36
  #
37
37
  # post.title = "On the migration of ducks"
@@ -39,7 +39,7 @@ module ActiveRecord
39
39
  #
40
40
  # post.save
41
41
  # post.reload
42
- # post.title # => "On the migration of ducks"
42
+ # post.title # => "On the migration of ducks"
43
43
  # post.author.name # => "Eloy Duran"
44
44
  #
45
45
  # Destroying an associated model, as part of the parent's save action, is as
@@ -49,6 +49,7 @@ module ActiveRecord
49
49
  # post.author.marked_for_destruction? # => true
50
50
  #
51
51
  # Note that the model is _not_ yet removed from the database:
52
+ #
52
53
  # id = post.author.id
53
54
  # Author.find_by_id(id).nil? # => false
54
55
  #
@@ -56,40 +57,49 @@ module ActiveRecord
56
57
  # post.reload.author # => nil
57
58
  #
58
59
  # Now it _is_ removed from the database:
60
+ #
59
61
  # Author.find_by_id(id).nil? # => true
60
62
  #
61
63
  # === One-to-many Example
62
64
  #
63
- # Consider a Post model with many Comments:
65
+ # When <tt>:autosave</tt> is not declared new children are saved when their parent is saved:
64
66
  #
65
67
  # class Post
66
- # has_many :comments, :autosave => true
68
+ # has_many :comments # :autosave option is no declared
67
69
  # end
68
70
  #
69
- # Saving changes to the parent and its associated model can now be performed
70
- # automatically _and_ atomically:
71
+ # post = Post.new(:title => 'ruby rocks')
72
+ # post.comments.build(:body => 'hello world')
73
+ # post.save # => saves both post and comment
71
74
  #
72
- # post = Post.find(1)
73
- # post.title # => "The current global position of migrating ducks"
74
- # post.comments.first.body # => "Wow, awesome info thanks!"
75
- # post.comments.last.body # => "Actually, your article should be named differently."
75
+ # post = Post.create(:title => 'ruby rocks')
76
+ # post.comments.build(:body => 'hello world')
77
+ # post.save # => saves both post and comment
76
78
  #
77
- # post.title = "On the migration of ducks"
78
- # post.comments.last.body = "Actually, your article should be named differently. [UPDATED]: You are right, thanks."
79
+ # post = Post.create(:title => 'ruby rocks')
80
+ # post.comments.create(:body => 'hello world')
81
+ # post.save # => saves both post and comment
79
82
  #
80
- # post.save
81
- # post.reload
82
- # post.title # => "On the migration of ducks"
83
- # post.comments.last.body # => "Actually, your article should be named differently. [UPDATED]: You are right, thanks."
83
+ # When <tt>:autosave</tt> is true all children is saved, no matter whether they are new records:
84
+ #
85
+ # class Post
86
+ # has_many :comments, :autosave => true
87
+ # end
88
+ #
89
+ # post = Post.create(:title => 'ruby rocks')
90
+ # post.comments.create(:body => 'hello world')
91
+ # post.comments[0].body = 'hi everyone'
92
+ # post.save # => saves both post and comment, with 'hi everyone' as title
84
93
  #
85
- # Destroying one of the associated models members, as part of the parent's
86
- # save action, is as simple as marking it for destruction:
94
+ # Destroying one of the associated models as part of the parent's save action
95
+ # is as simple as marking it for destruction:
87
96
  #
88
97
  # post.comments.last.mark_for_destruction
89
98
  # post.comments.last.marked_for_destruction? # => true
90
99
  # post.comments.length # => 2
91
100
  #
92
101
  # Note that the model is _not_ yet removed from the database:
102
+ #
93
103
  # id = post.comments.last.id
94
104
  # Comment.find_by_id(id).nil? # => false
95
105
  #
@@ -97,37 +107,12 @@ module ActiveRecord
97
107
  # post.reload.comments.length # => 1
98
108
  #
99
109
  # Now it _is_ removed from the database:
110
+ #
100
111
  # Comment.find_by_id(id).nil? # => true
101
112
  #
102
113
  # === Validation
103
114
  #
104
- # Validation is performed on the parent as usual, but also on all autosave
105
- # enabled associations. If any of the associations fail validation, its
106
- # error messages will be applied on the parents errors object and validation
107
- # of the parent will fail.
108
- #
109
- # Consider a Post model with Author which validates the presence of its name
110
- # attribute:
111
- #
112
- # class Post
113
- # has_one :author, :autosave => true
114
- # end
115
- #
116
- # class Author
117
- # validates_presence_of :name
118
- # end
119
- #
120
- # post = Post.find(1)
121
- # post.author.name = ''
122
- # post.save # => false
123
- # post.errors # => #<ActiveRecord::Errors:0x174498c @errors={"author.name"=>["can't be blank"]}, @base=#<Post ...>>
124
- #
125
- # No validations will be performed on the associated models when validations
126
- # are skipped for the parent:
127
- #
128
- # post = Post.find(1)
129
- # post.author.name = ''
130
- # post.save(:validate => false) # => true
115
+ # Children records are validated unless <tt>:validate</tt> is +false+.
131
116
  module AutosaveAssociation
132
117
  extend ActiveSupport::Concern
133
118
 
@@ -155,11 +140,12 @@ module ActiveRecord
155
140
  CODE
156
141
  end
157
142
 
158
- # Adds a validate and save callback for the association as specified by
143
+ # Adds validation and save callbacks for the association as specified by
159
144
  # the +reflection+.
160
145
  #
161
- # For performance reasons, we don't check whether to validate at runtime,
162
- # but instead only define the method and callback when needed. However,
146
+ # For performance reasons, we don't check whether to validate at runtime.
147
+ # However the validation and callback methods are lazy and those methods
148
+ # get created when they are invoked for the very first time. However,
163
149
  # this can change, for instance, when using nested attributes, which is
164
150
  # called _after_ the association has been defined. Since we don't want
165
151
  # the callbacks to get defined multiple times, there are guards that
@@ -197,14 +183,15 @@ module ActiveRecord
197
183
  end
198
184
  end
199
185
 
200
- # Reloads the attributes of the object as usual and removes a mark for destruction.
186
+ # Reloads the attributes of the object as usual and clears <tt>marked_for_destruction</tt> flag.
201
187
  def reload(options = nil)
202
188
  @marked_for_destruction = false
203
189
  super
204
190
  end
205
191
 
206
192
  # Marks this record to be destroyed as part of the parents save transaction.
207
- # This does _not_ actually destroy the record yet, rather it will be destroyed when <tt>parent.save</tt> is called.
193
+ # This does _not_ actually destroy the record instantly, rather child record will be destroyed
194
+ # when <tt>parent.save</tt> is called.
208
195
  #
209
196
  # Only useful if the <tt>:autosave</tt> option on the parent is enabled for this associated model.
210
197
  def mark_for_destruction
@@ -223,7 +210,7 @@ module ActiveRecord
223
210
  def changed_for_autosave?
224
211
  new_record? || changed? || marked_for_destruction? || nested_records_changed_for_autosave?
225
212
  end
226
-
213
+
227
214
  private
228
215
 
229
216
  # Returns the record for an association collection that should be validated
@@ -244,12 +231,12 @@ module ActiveRecord
244
231
  def nested_records_changed_for_autosave?
245
232
  self.class.reflect_on_all_autosave_associations.any? do |reflection|
246
233
  association = association_instance_get(reflection.name)
247
- association && Array.wrap(association.target).any?(&:changed_for_autosave?)
234
+ association && Array.wrap(association.target).any? { |a| a.changed_for_autosave? }
248
235
  end
249
236
  end
250
-
237
+
251
238
  # Validate the association if <tt>:validate</tt> or <tt>:autosave</tt> is
252
- # turned on for the association specified by +reflection+.
239
+ # turned on for the association.
253
240
  def validate_single_association(reflection)
254
241
  if (association = association_instance_get(reflection.name)) && !association.target.nil?
255
242
  association_valid?(reflection, association)
@@ -357,14 +344,9 @@ module ActiveRecord
357
344
  end
358
345
  end
359
346
 
360
- # Saves the associated record if it's new or <tt>:autosave</tt> is enabled
361
- # on the association.
347
+ # Saves the associated record if it's new or <tt>:autosave</tt> is enabled.
362
348
  #
363
- # In addition, it will destroy the association if it was marked for
364
- # destruction with mark_for_destruction.
365
- #
366
- # This all happens inside a transaction, _if_ the Transactions module is included into
367
- # ActiveRecord::Base after the AutosaveAssociation module, which it does by default.
349
+ # In addition, it will destroy the association if it was marked for destruction.
368
350
  def save_belongs_to_association(reflection)
369
351
  if (association = association_instance_get(reflection.name)) && !association.destroyed?
370
352
  autosave = reflection.options[:autosave]
@@ -384,4 +366,4 @@ module ActiveRecord
384
366
  end
385
367
  end
386
368
  end
387
- end
369
+ end
@@ -26,17 +26,19 @@ require 'active_record/log_subscriber'
26
26
  module ActiveRecord #:nodoc:
27
27
  # = Active Record
28
28
  #
29
- # Active Record objects don't specify their attributes directly, but rather infer them from the table definition with
30
- # which they're linked. Adding, removing, and changing attributes and their type is done directly in the database. Any change
31
- # is instantly reflected in the Active Record objects. The mapping that binds a given Active Record class to a certain
29
+ # Active Record objects don't specify their attributes directly, but rather infer them from
30
+ # the table definition with which they're linked. Adding, removing, and changing attributes
31
+ # and their type is done directly in the database. Any change is instantly reflected in the
32
+ # Active Record objects. The mapping that binds a given Active Record class to a certain
32
33
  # database table will happen automatically in most common cases, but can be overwritten for the uncommon ones.
33
34
  #
34
35
  # See the mapping rules in table_name and the full example in link:files/README.html for more insight.
35
36
  #
36
37
  # == Creation
37
38
  #
38
- # Active Records accept constructor parameters either in a hash or as a block. The hash method is especially useful when
39
- # you're receiving the data from somewhere else, like an HTTP request. It works like this:
39
+ # Active Records accept constructor parameters either in a hash or as a block. The hash
40
+ # method is especially useful when you're receiving the data from somewhere else, like an
41
+ # HTTP request. It works like this:
40
42
  #
41
43
  # user = User.new(:name => "David", :occupation => "Code Artist")
42
44
  # user.name # => "David"
@@ -75,14 +77,17 @@ module ActiveRecord #:nodoc:
75
77
  # end
76
78
  # end
77
79
  #
78
- # The <tt>authenticate_unsafely</tt> method inserts the parameters directly into the query and is thus susceptible to SQL-injection
79
- # attacks if the <tt>user_name</tt> and +password+ parameters come directly from an HTTP request. The <tt>authenticate_safely</tt> and
80
- # <tt>authenticate_safely_simply</tt> both will sanitize the <tt>user_name</tt> and +password+ before inserting them in the query,
81
- # which will ensure that an attacker can't escape the query and fake the login (or worse).
80
+ # The <tt>authenticate_unsafely</tt> method inserts the parameters directly into the query
81
+ # and is thus susceptible to SQL-injection attacks if the <tt>user_name</tt> and +password+
82
+ # parameters come directly from an HTTP request. The <tt>authenticate_safely</tt> and
83
+ # <tt>authenticate_safely_simply</tt> both will sanitize the <tt>user_name</tt> and +password+
84
+ # before inserting them in the query, which will ensure that an attacker can't escape the
85
+ # query and fake the login (or worse).
82
86
  #
83
- # When using multiple parameters in the conditions, it can easily become hard to read exactly what the fourth or fifth
84
- # question mark is supposed to represent. In those cases, you can resort to named bind variables instead. That's done by replacing
85
- # the question marks with symbols and supplying a hash with values for the matching symbol keys:
87
+ # When using multiple parameters in the conditions, it can easily become hard to read exactly
88
+ # what the fourth or fifth question mark is supposed to represent. In those cases, you can
89
+ # resort to named bind variables instead. That's done by replacing the question marks with
90
+ # symbols and supplying a hash with values for the matching symbol keys:
86
91
  #
87
92
  # Company.where(
88
93
  # "id = :id AND name = :name AND division = :division AND created_at > :accounting_date",
@@ -103,18 +108,19 @@ module ActiveRecord #:nodoc:
103
108
  #
104
109
  # Student.where(:grade => [9,11,12])
105
110
  #
106
- # When joining tables, nested hashes or keys written in the form 'table_name.column_name' can be used to qualify the table name of a
107
- # particular condition. For instance:
111
+ # When joining tables, nested hashes or keys written in the form 'table_name.column_name'
112
+ # can be used to qualify the table name of a particular condition. For instance:
108
113
  #
109
114
  # Student.joins(:schools).where(:schools => { :type => 'public' })
110
115
  # Student.joins(:schools).where('schools.type' => 'public' )
111
116
  #
112
117
  # == Overwriting default accessors
113
118
  #
114
- # All column values are automatically available through basic accessors on the Active Record object, but sometimes you
115
- # want to specialize this behavior. This can be done by overwriting the default accessors (using the same
116
- # name as the attribute) and calling <tt>read_attribute(attr_name)</tt> and <tt>write_attribute(attr_name, value)</tt> to actually change things.
117
- # Example:
119
+ # All column values are automatically available through basic accessors on the Active Record
120
+ # object, but sometimes you want to specialize this behavior. This can be done by overwriting
121
+ # the default accessors (using the same name as the attribute) and calling
122
+ # <tt>read_attribute(attr_name)</tt> and <tt>write_attribute(attr_name, value)</tt> to actually
123
+ # change things.
118
124
  #
119
125
  # class Song < ActiveRecord::Base
120
126
  # # Uses an integer of seconds to hold the length of the song
@@ -128,8 +134,8 @@ module ActiveRecord #:nodoc:
128
134
  # end
129
135
  # end
130
136
  #
131
- # You can alternatively use <tt>self[:attribute]=(value)</tt> and <tt>self[:attribute]</tt> instead of <tt>write_attribute(:attribute, value)</tt> and
132
- # <tt>read_attribute(:attribute)</tt> as a shorter form.
137
+ # You can alternatively use <tt>self[:attribute]=(value)</tt> and <tt>self[:attribute]</tt>
138
+ # instead of <tt>write_attribute(:attribute, value)</tt> and <tt>read_attribute(:attribute)</tt>.
133
139
  #
134
140
  # == Attribute query methods
135
141
  #
@@ -147,34 +153,43 @@ module ActiveRecord #:nodoc:
147
153
  #
148
154
  # == Accessing attributes before they have been typecasted
149
155
  #
150
- # Sometimes you want to be able to read the raw attribute data without having the column-determined typecast run its course first.
151
- # That can be done by using the <tt><attribute>_before_type_cast</tt> accessors that all attributes have. For example, if your Account model
152
- # has a <tt>balance</tt> attribute, you can call <tt>account.balance_before_type_cast</tt> or <tt>account.id_before_type_cast</tt>.
156
+ # Sometimes you want to be able to read the raw attribute data without having the column-determined
157
+ # typecast run its course first. That can be done by using the <tt><attribute>_before_type_cast</tt>
158
+ # accessors that all attributes have. For example, if your Account model has a <tt>balance</tt> attribute,
159
+ # you can call <tt>account.balance_before_type_cast</tt> or <tt>account.id_before_type_cast</tt>.
153
160
  #
154
- # This is especially useful in validation situations where the user might supply a string for an integer field and you want to display
155
- # the original string back in an error message. Accessing the attribute normally would typecast the string to 0, which isn't what you
156
- # want.
161
+ # This is especially useful in validation situations where the user might supply a string for an
162
+ # integer field and you want to display the original string back in an error message. Accessing the
163
+ # attribute normally would typecast the string to 0, which isn't what you want.
157
164
  #
158
165
  # == Dynamic attribute-based finders
159
166
  #
160
- # Dynamic attribute-based finders are a cleaner way of getting (and/or creating) objects by simple queries without turning to SQL. They work by
161
- # appending the name of an attribute to <tt>find_by_</tt>, <tt>find_last_by_</tt>, or <tt>find_all_by_</tt>, so you get finders like <tt>Person.find_by_user_name</tt>,
162
- # <tt>Person.find_all_by_last_name</tt>, and <tt>Payment.find_by_transaction_id</tt>. So instead of writing
167
+ # Dynamic attribute-based finders are a cleaner way of getting (and/or creating) objects
168
+ # by simple queries without turning to SQL. They work by appending the name of an attribute
169
+ # to <tt>find_by_</tt>, <tt>find_last_by_</tt>, or <tt>find_all_by_</tt> and thus produces finders
170
+ # like <tt>Person.find_by_user_name</tt>, <tt>Person.find_all_by_last_name</tt>, and
171
+ # <tt>Payment.find_by_transaction_id</tt>. Instead of writing
163
172
  # <tt>Person.where(:user_name => user_name).first</tt>, you just do <tt>Person.find_by_user_name(user_name)</tt>.
164
- # And instead of writing <tt>Person.where(:last_name => last_name).all</tt>, you just do <tt>Person.find_all_by_last_name(last_name)</tt>.
173
+ # And instead of writing <tt>Person.where(:last_name => last_name).all</tt>, you just do
174
+ # <tt>Person.find_all_by_last_name(last_name)</tt>.
165
175
  #
166
- # It's also possible to use multiple attributes in the same find by separating them with "_and_", so you get finders like
167
- # <tt>Person.find_by_user_name_and_password</tt> or even <tt>Payment.find_by_purchaser_and_state_and_country</tt>. So instead of writing
168
- # <tt>Person.where(:user_name => user_name, :password => password).first</tt>, you just do
169
- # <tt>Person.find_by_user_name_and_password(user_name, password)</tt>.
176
+ # It's also possible to use multiple attributes in the same find by separating them with "_and_".
170
177
  #
171
- # It's even possible to call these dynamic finder methods on relations and named scopes. For example :
178
+ # Person.where(:user_name => user_name, :password => password).first
179
+ # Person.find_by_user_name_and_password #with dynamic finder
180
+ #
181
+ # Person.where(:user_name => user_name, :password => password, :gender => 'male').first
182
+ # Payment.find_by_user_name_and_password_and_gender
183
+ #
184
+ # It's even possible to call these dynamic finder methods on relations and named scopes.
172
185
  #
173
186
  # Payment.order("created_on").find_all_by_amount(50)
174
187
  # Payment.pending.find_last_by_amount(100)
175
188
  #
176
- # The same dynamic finder style can be used to create the object if it doesn't already exist. This dynamic finder is called with
177
- # <tt>find_or_create_by_</tt> and will return the object if it already exists and otherwise creates it, then returns it. Protected attributes won't be set unless they are given in a block. For example:
189
+ # The same dynamic finder style can be used to create the object if it doesn't already exist.
190
+ # This dynamic finder is called with <tt>find_or_create_by_</tt> and will return the object if
191
+ # it already exists and otherwise creates it, then returns it. Protected attributes won't be set
192
+ # unless they are given in a block.
178
193
  #
179
194
  # # No 'Summer' tag exists
180
195
  # Tag.find_or_create_by_name("Summer") # equal to Tag.create(:name => "Summer")
@@ -185,23 +200,33 @@ module ActiveRecord #:nodoc:
185
200
  # # Now 'Bob' exist and is an 'admin'
186
201
  # User.find_or_create_by_name('Bob', :age => 40) { |u| u.admin = true }
187
202
  #
188
- # Use the <tt>find_or_initialize_by_</tt> finder if you want to return a new record without saving it first. Protected attributes won't be set unless they are given in a block. For example:
203
+ # Use the <tt>find_or_initialize_by_</tt> finder if you want to return a new record without
204
+ # saving it first. Protected attributes won't be set unless they are given in a block.
189
205
  #
190
206
  # # No 'Winter' tag exists
191
207
  # winter = Tag.find_or_initialize_by_name("Winter")
192
208
  # winter.new_record? # true
193
209
  #
194
210
  # To find by a subset of the attributes to be used for instantiating a new object, pass a hash instead of
195
- # a list of parameters. For example:
211
+ # a list of parameters.
196
212
  #
197
213
  # Tag.find_or_create_by_name(:name => "rails", :creator => current_user)
198
214
  #
199
- # That will either find an existing tag named "rails", or create a new one while setting the user that created it.
215
+ # That will either find an existing tag named "rails", or create a new one while setting the
216
+ # user that created it.
217
+ #
218
+ # Just like <tt>find_by_*</tt>, you can also use <tt>scoped_by_*</tt> to retrieve data. The good thing about
219
+ # using this feature is that the very first time result is returned using <tt>method_missing</tt> technique
220
+ # but after that the method is declared on the class. Henceforth <tt>method_missing</tt> will not be hit.
221
+ #
222
+ # User.scoped_by_user_name('David')
200
223
  #
201
224
  # == Saving arrays, hashes, and other non-mappable objects in text columns
202
225
  #
203
- # Active Record can serialize any object in text columns using YAML. To do so, you must specify this with a call to the class method +serialize+.
204
- # This makes it possible to store arrays, hashes, and other non-mappable objects without doing any additional work. Example:
226
+ # Active Record can serialize any object in text columns using YAML. To do so, you must
227
+ # specify this with a call to the class method +serialize+.
228
+ # This makes it possible to store arrays, hashes, and other non-mappable objects without doing
229
+ # any additional work.
205
230
  #
206
231
  # class User < ActiveRecord::Base
207
232
  # serialize :preferences
@@ -210,8 +235,8 @@ module ActiveRecord #:nodoc:
210
235
  # user = User.create(:preferences => { "background" => "black", "display" => large })
211
236
  # User.find(user.id).preferences # => { "background" => "black", "display" => large }
212
237
  #
213
- # You can also specify a class option as the second parameter that'll raise an exception if a serialized object is retrieved as a
214
- # descendant of a class not in the hierarchy. Example:
238
+ # You can also specify a class option as the second parameter that'll raise an exception
239
+ # if a serialized object is retrieved as a descendant of a class not in the hierarchy.
215
240
  #
216
241
  # class User < ActiveRecord::Base
217
242
  # serialize :preferences, Hash
@@ -222,52 +247,63 @@ module ActiveRecord #:nodoc:
222
247
  #
223
248
  # == Single table inheritance
224
249
  #
225
- # Active Record allows inheritance by storing the name of the class in a column that by default is named "type" (can be changed
226
- # by overwriting <tt>Base.inheritance_column</tt>). This means that an inheritance looking like this:
250
+ # Active Record allows inheritance by storing the name of the class in a column that by
251
+ # default is named "type" (can be changed by overwriting <tt>Base.inheritance_column</tt>).
252
+ # This means that an inheritance looking like this:
227
253
  #
228
254
  # class Company < ActiveRecord::Base; end
229
255
  # class Firm < Company; end
230
256
  # class Client < Company; end
231
257
  # class PriorityClient < Client; end
232
258
  #
233
- # When you do <tt>Firm.create(:name => "37signals")</tt>, this record will be saved in the companies table with type = "Firm". You can then
234
- # fetch this row again using <tt>Company.where(:name => '37signals').first</tt> and it will return a Firm object.
259
+ # When you do <tt>Firm.create(:name => "37signals")</tt>, this record will be saved in
260
+ # the companies table with type = "Firm". You can then fetch this row again using
261
+ # <tt>Company.where(:name => '37signals').first</tt> and it will return a Firm object.
235
262
  #
236
- # If you don't have a type column defined in your table, single-table inheritance won't be triggered. In that case, it'll work just
237
- # like normal subclasses with no special magic for differentiating between them or reloading the right type with find.
263
+ # If you don't have a type column defined in your table, single-table inheritance won't
264
+ # be triggered. In that case, it'll work just like normal subclasses with no special magic
265
+ # for differentiating between them or reloading the right type with find.
238
266
  #
239
267
  # Note, all the attributes for all the cases are kept in the same table. Read more:
240
268
  # http://www.martinfowler.com/eaaCatalog/singleTableInheritance.html
241
269
  #
242
270
  # == Connection to multiple databases in different models
243
271
  #
244
- # Connections are usually created through ActiveRecord::Base.establish_connection and retrieved by ActiveRecord::Base.connection.
245
- # All classes inheriting from ActiveRecord::Base will use this connection. But you can also set a class-specific connection.
246
- # For example, if Course is an ActiveRecord::Base, but resides in a different database, you can just say <tt>Course.establish_connection</tt>
272
+ # Connections are usually created through ActiveRecord::Base.establish_connection and retrieved
273
+ # by ActiveRecord::Base.connection. All classes inheriting from ActiveRecord::Base will use this
274
+ # connection. But you can also set a class-specific connection. For example, if Course is an
275
+ # ActiveRecord::Base, but resides in a different database, you can just say <tt>Course.establish_connection</tt>
247
276
  # and Course and all of its subclasses will use this connection instead.
248
277
  #
249
- # This feature is implemented by keeping a connection pool in ActiveRecord::Base that is a Hash indexed by the class. If a connection is
250
- # requested, the retrieve_connection method will go up the class-hierarchy until a connection is found in the connection pool.
278
+ # This feature is implemented by keeping a connection pool in ActiveRecord::Base that is
279
+ # a Hash indexed by the class. If a connection is requested, the retrieve_connection method
280
+ # will go up the class-hierarchy until a connection is found in the connection pool.
251
281
  #
252
282
  # == Exceptions
253
283
  #
254
284
  # * ActiveRecordError - Generic error class and superclass of all other errors raised by Active Record.
255
285
  # * AdapterNotSpecified - The configuration hash used in <tt>establish_connection</tt> didn't include an
256
286
  # <tt>:adapter</tt> key.
257
- # * AdapterNotFound - The <tt>:adapter</tt> key used in <tt>establish_connection</tt> specified a non-existent adapter
287
+ # * AdapterNotFound - The <tt>:adapter</tt> key used in <tt>establish_connection</tt> specified a
288
+ # non-existent adapter
258
289
  # (or a bad spelling of an existing one).
259
- # * AssociationTypeMismatch - The object assigned to the association wasn't of the type specified in the association definition.
290
+ # * AssociationTypeMismatch - The object assigned to the association wasn't of the type
291
+ # specified in the association definition.
260
292
  # * SerializationTypeMismatch - The serialized object wasn't of the class specified as the second parameter.
261
- # * ConnectionNotEstablished+ - No connection has been established. Use <tt>establish_connection</tt> before querying.
293
+ # * ConnectionNotEstablished+ - No connection has been established. Use <tt>establish_connection</tt>
294
+ # before querying.
262
295
  # * RecordNotFound - No record responded to the +find+ method. Either the row with the given ID doesn't exist
263
296
  # or the row didn't meet the additional restrictions. Some +find+ calls do not raise this exception to signal
264
297
  # nothing was found, please check its documentation for further details.
265
298
  # * StatementInvalid - The database server rejected the SQL statement. The precise error is added in the message.
266
299
  # * MultiparameterAssignmentErrors - Collection of errors that occurred during a mass assignment using the
267
- # <tt>attributes=</tt> method. The +errors+ property of this exception contains an array of AttributeAssignmentError
300
+ # <tt>attributes=</tt> method. The +errors+ property of this exception contains an array of
301
+ # AttributeAssignmentError
268
302
  # objects that should be inspected to determine which attributes triggered the errors.
269
- # * AttributeAssignmentError - An error occurred while doing a mass assignment through the <tt>attributes=</tt> method.
270
- # You can inspect the +attribute+ property of the exception object to determine which attribute triggered the error.
303
+ # * AttributeAssignmentError - An error occurred while doing a mass assignment through the
304
+ # <tt>attributes=</tt> method.
305
+ # You can inspect the +attribute+ property of the exception object to determine which attribute
306
+ # triggered the error.
271
307
  #
272
308
  # *Note*: The attributes listed are class-level attributes (accessible from both the class and instance level).
273
309
  # So it's possible to assign a logger to the class through <tt>Base.logger=</tt> which will then be used by all
@@ -275,8 +311,9 @@ module ActiveRecord #:nodoc:
275
311
  class Base
276
312
  ##
277
313
  # :singleton-method:
278
- # Accepts a logger conforming to the interface of Log4r or the default Ruby 1.8+ Logger class, which is then passed
279
- # on to any new database connections made and which can be retrieved on both a class and instance level by calling +logger+.
314
+ # Accepts a logger conforming to the interface of Log4r or the default Ruby 1.8+ Logger class,
315
+ # which is then passed on to any new database connections made and which can be retrieved on both
316
+ # a class and instance level by calling +logger+.
280
317
  cattr_accessor :logger, :instance_writer => false
281
318
 
282
319
  class << self
@@ -323,21 +360,24 @@ module ActiveRecord #:nodoc:
323
360
 
324
361
  ##
325
362
  # :singleton-method:
326
- # Accessor for the prefix type that will be prepended to every primary key column name. The options are :table_name and
327
- # :table_name_with_underscore. If the first is specified, the Product class will look for "productid" instead of "id" as
328
- # the primary column. If the latter is specified, the Product class will look for "product_id" instead of "id". Remember
363
+ # Accessor for the prefix type that will be prepended to every primary key column name.
364
+ # The options are :table_name and :table_name_with_underscore. If the first is specified,
365
+ # the Product class will look for "productid" instead of "id" as the primary column. If the
366
+ # latter is specified, the Product class will look for "product_id" instead of "id". Remember
329
367
  # that this is a global setting for all Active Records.
330
368
  cattr_accessor :primary_key_prefix_type, :instance_writer => false
331
369
  @@primary_key_prefix_type = nil
332
370
 
333
371
  ##
334
372
  # :singleton-method:
335
- # Accessor for the name of the prefix string to prepend to every table name. So if set to "basecamp_", all
336
- # table names will be named like "basecamp_projects", "basecamp_people", etc. This is a convenient way of creating a namespace
337
- # for tables in a shared database. By default, the prefix is the empty string.
373
+ # Accessor for the name of the prefix string to prepend to every table name. So if set
374
+ # to "basecamp_", all table names will be named like "basecamp_projects", "basecamp_people",
375
+ # etc. This is a convenient way of creating a namespace for tables in a shared database.
376
+ # By default, the prefix is the empty string.
338
377
  #
339
- # If you are organising your models within modules you can add a prefix to the models within a namespace by defining
340
- # a singleton method in the parent module called table_name_prefix which returns your chosen prefix.
378
+ # If you are organising your models within modules you can add a prefix to the models within
379
+ # a namespace by defining a singleton method in the parent module called table_name_prefix which
380
+ # returns your chosen prefix.
341
381
  class_attribute :table_name_prefix, :instance_writer => false
342
382
  self.table_name_prefix = ""
343
383
 
@@ -358,8 +398,8 @@ module ActiveRecord #:nodoc:
358
398
 
359
399
  ##
360
400
  # :singleton-method:
361
- # Determines whether to use Time.local (using :local) or Time.utc (using :utc) when pulling dates and times from the database.
362
- # This is set to :local by default.
401
+ # Determines whether to use Time.local (using :local) or Time.utc (using :utc) when pulling
402
+ # dates and times from the database. This is set to :local by default.
363
403
  cattr_accessor :default_timezone, :instance_writer => false
364
404
  @@default_timezone = :local
365
405
 
@@ -476,9 +516,10 @@ module ActiveRecord #:nodoc:
476
516
  connection.select_value(sql, "#{name} Count").to_i
477
517
  end
478
518
 
479
- # Attributes listed as readonly can be set for a new record, but will be ignored in database updates afterwards.
519
+ # Attributes listed as readonly will be used to create a new record but update operations will
520
+ # ignore these fields.
480
521
  def attr_readonly(*attributes)
481
- write_inheritable_attribute(:attr_readonly, Set.new(attributes.map(&:to_s)) + (readonly_attributes || []))
522
+ write_inheritable_attribute(:attr_readonly, Set.new(attributes.map { |a| a.to_s }) + (readonly_attributes || []))
482
523
  end
483
524
 
484
525
  # Returns an array of all the attributes that have been specified as readonly.
@@ -505,15 +546,18 @@ module ActiveRecord #:nodoc:
505
546
  serialized_attributes[attr_name.to_s] = class_name
506
547
  end
507
548
 
508
- # Returns a hash of all the attributes that have been specified for serialization as keys and their class restriction as values.
549
+ # Returns a hash of all the attributes that have been specified for serialization as
550
+ # keys and their class restriction as values.
509
551
  def serialized_attributes
510
552
  read_inheritable_attribute(:attr_serialized) or write_inheritable_attribute(:attr_serialized, {})
511
553
  end
512
554
 
513
- # Guesses the table name (in forced lower-case) based on the name of the class in the inheritance hierarchy descending
514
- # directly from ActiveRecord::Base. So if the hierarchy looks like: Reply < Message < ActiveRecord::Base, then Message is used
515
- # to guess the table name even when called on Reply. The rules used to do the guess are handled by the Inflector class
516
- # in Active Support, which knows almost all common English inflections. You can add new inflections in config/initializers/inflections.rb.
555
+ # Guesses the table name (in forced lower-case) based on the name of the class in the
556
+ # inheritance hierarchy descending directly from ActiveRecord::Base. So if the hierarchy
557
+ # looks like: Reply < Message < ActiveRecord::Base, then Message is used
558
+ # to guess the table name even when called on Reply. The rules used to do the guess
559
+ # are handled by the Inflector class in Active Support, which knows almost all common
560
+ # English inflections. You can add new inflections in config/initializers/inflections.rb.
517
561
  #
518
562
  # Nested classes are given table names prefixed by the singular form of
519
563
  # the parent's table name. Enclosing modules are not considered.
@@ -561,8 +605,8 @@ module ActiveRecord #:nodoc:
561
605
  (parents.detect{ |p| p.respond_to?(:table_name_prefix) } || self).table_name_prefix
562
606
  end
563
607
 
564
- # Defines the column name for use with single table inheritance
565
- # -- can be set in subclasses like so: self.inheritance_column = "type_id"
608
+ # Defines the column name for use with single table inheritance. Use
609
+ # <tt>set_inheritance_column</tt> to set a different value.
566
610
  def inheritance_column
567
611
  @inheritance_column ||= "type".freeze
568
612
  end
@@ -579,8 +623,8 @@ module ActiveRecord #:nodoc:
579
623
  default
580
624
  end
581
625
 
582
- # Sets the table name to use to the given value, or (if the value
583
- # is nil or false) to the value returned by the given block.
626
+ # Sets the table name. If the value is nil or false then the value returned by the given
627
+ # block is used.
584
628
  #
585
629
  # class Project < ActiveRecord::Base
586
630
  # set_table_name "project"
@@ -803,7 +847,7 @@ module ActiveRecord #:nodoc:
803
847
  end
804
848
 
805
849
  def arel_table
806
- @arel_table ||= Arel::Table.new(table_name, :engine => arel_engine)
850
+ @arel_table ||= Arel::Table.new(table_name, arel_engine)
807
851
  end
808
852
 
809
853
  def arel_engine
@@ -874,7 +918,11 @@ module ActiveRecord #:nodoc:
874
918
  self
875
919
  else
876
920
  begin
877
- compute_type(type_name)
921
+ if store_full_sti_class
922
+ ActiveSupport::Dependencies.constantize(type_name)
923
+ else
924
+ compute_type(type_name)
925
+ end
878
926
  rescue NameError
879
927
  raise SubclassNotFound,
880
928
  "The single-table inheritance mechanism failed to locate the subclass: '#{type_name}'. " +
@@ -923,15 +971,15 @@ module ActiveRecord #:nodoc:
923
971
  end
924
972
  end
925
973
 
926
- # Enables dynamic finders like <tt>find_by_user_name(user_name)</tt> and <tt>find_by_user_name_and_password(user_name, password)</tt>
927
- # that are turned into <tt>where(:user_name => user_name).first</tt> and <tt>where(:user_name => user_name, :password => :password).first</tt>
928
- # respectively. Also works for <tt>all</tt> by using <tt>find_all_by_amount(50)</tt> that is turned into <tt>where(:amount => 50).all</tt>.
974
+ # Enables dynamic finders like <tt>User.find_by_user_name(user_name)</tt> and
975
+ # <tt>User.scoped_by_user_name(user_name). Refer to Dynamic attribute-based finders
976
+ # section at the top of this file for more detailed information.
929
977
  #
930
- # It's even possible to use all the additional parameters to +find+. For example, the full interface for +find_all_by_amount+
931
- # is actually <tt>find_all_by_amount(amount, options)</tt>.
978
+ # It's even possible to use all the additional parameters to +find+. For example, the
979
+ # full interface for +find_all_by_amount+ is actually <tt>find_all_by_amount(amount, options)</tt>.
932
980
  #
933
- # Each dynamic finder, scope or initializer/creator is also defined in the class after it is first invoked, so that future
934
- # attempts to use it do not run through method_missing.
981
+ # Each dynamic finder using <tt>scoped_by_*</tt> is also defined in the class after it
982
+ # is first invoked, so that future attempts to use it do not run through method_missing.
935
983
  def method_missing(method_id, *arguments, &block)
936
984
  if match = DynamicFinderMatch.match(method_id)
937
985
  attribute_names = match.attribute_names
@@ -991,8 +1039,8 @@ module ActiveRecord #:nodoc:
991
1039
  end
992
1040
 
993
1041
  protected
994
- # Scope parameters to method calls within the block. Takes a hash of method_name => parameters hash.
995
- # method_name may be <tt>:find</tt> or <tt>:create</tt>. <tt>:find</tt> parameter is <tt>Relation</tt> while
1042
+ # with_scope lets you apply options to inner block incrementally. It takes a hash and the keys must be
1043
+ # <tt>:find</tt> or <tt>:create</tt>. <tt>:find</tt> parameter is <tt>Relation</tt> while
996
1044
  # <tt>:create</tt> parameters are an attributes hash.
997
1045
  #
998
1046
  # class Article < ActiveRecord::Base
@@ -1037,8 +1085,7 @@ module ActiveRecord #:nodoc:
1037
1085
  # end
1038
1086
  # end
1039
1087
  #
1040
- # *Note*: the +:find+ scope also has effect on update and deletion methods,
1041
- # like +update_all+ and +delete_all+.
1088
+ # *Note*: the +:find+ scope also has effect on update and deletion methods, like +update_all+ and +delete_all+.
1042
1089
  def with_scope(method_scoping = {}, action = :merge, &block)
1043
1090
  method_scoping = method_scoping.method_scoping if method_scoping.respond_to?(:method_scoping)
1044
1091
 
@@ -1104,6 +1151,16 @@ MSG
1104
1151
  # class Person < ActiveRecord::Base
1105
1152
  # default_scope order('last_name, first_name')
1106
1153
  # end
1154
+ #
1155
+ # <tt>default_scope</tt> is also applied while creating/building a record. It is not
1156
+ # applied while updating a record.
1157
+ #
1158
+ # class Article < ActiveRecord::Base
1159
+ # default_scope where(:published => true)
1160
+ # end
1161
+ #
1162
+ # Article.new.published # => true
1163
+ # Article.create.published # => true
1107
1164
  def default_scope(options = {})
1108
1165
  self.default_scoping << construct_finder_arel(options, default_scoping.pop)
1109
1166
  end
@@ -1118,7 +1175,7 @@ MSG
1118
1175
  if type_name.match(/^::/)
1119
1176
  # If the type is prefixed with a scope operator then we assume that
1120
1177
  # the type_name is an absolute reference.
1121
- type_name.constantize
1178
+ ActiveSupport::Dependencies.constantize(type_name)
1122
1179
  else
1123
1180
  # Build a list of candidates to search for
1124
1181
  candidates = []
@@ -1127,7 +1184,7 @@ MSG
1127
1184
 
1128
1185
  candidates.each do |candidate|
1129
1186
  begin
1130
- constant = candidate.constantize
1187
+ constant = ActiveSupport::Dependencies.constantize(candidate)
1131
1188
  return constant if candidate == constant.to_s
1132
1189
  rescue NameError => e
1133
1190
  # We don't want to swallow NoMethodError < NameError errors
@@ -1233,7 +1290,7 @@ MSG
1233
1290
 
1234
1291
  table = Arel::Table.new(self.table_name, :engine => arel_engine, :as => default_table_name)
1235
1292
  builder = PredicateBuilder.new(arel_engine)
1236
- builder.build_from_hash(attrs, table).map(&:to_sql).join(' AND ')
1293
+ builder.build_from_hash(attrs, table).map{ |b| b.to_sql }.join(' AND ')
1237
1294
  end
1238
1295
  alias_method :sanitize_sql_hash, :sanitize_sql_hash_for_conditions
1239
1296
 
@@ -1357,7 +1414,7 @@ MSG
1357
1414
  # as it copies the object's attributes only, not its associations. The extent of a "deep" clone is
1358
1415
  # application specific and is therefore left to the application to implement according to its need.
1359
1416
  def initialize_copy(other)
1360
- callback(:after_initialize) if respond_to_without_attributes?(:after_initialize)
1417
+ _run_after_initialize_callbacks if respond_to?(:_run_after_initialize_callbacks)
1361
1418
  cloned_attributes = other.clone_attributes(:read_attribute_before_type_cast)
1362
1419
  cloned_attributes.delete(self.class.primary_key)
1363
1420
 
@@ -1607,10 +1664,11 @@ MSG
1607
1664
 
1608
1665
  private
1609
1666
 
1610
- # Sets the attribute used for single table inheritance to this class name if this is not the ActiveRecord::Base descendant.
1611
- # Considering the hierarchy Reply < Message < ActiveRecord::Base, this makes it possible to do Reply.new without having to
1612
- # set <tt>Reply[Reply.inheritance_column] = "Reply"</tt> yourself. No such attribute would be set for objects of the
1613
- # Message class in that example.
1667
+ # Sets the attribute used for single table inheritance to this class name if this is not the
1668
+ # ActiveRecord::Base descendant.
1669
+ # Considering the hierarchy Reply < Message < ActiveRecord::Base, this makes it possible to
1670
+ # do Reply.new without having to set <tt>Reply[Reply.inheritance_column] = "Reply"</tt> yourself.
1671
+ # No such attribute would be set for objects of the Message class in that example.
1614
1672
  def ensure_proper_type
1615
1673
  unless self.class.descends_from_active_record?
1616
1674
  write_attribute(self.class.inheritance_column, self.class.sti_name)
@@ -1659,8 +1717,9 @@ MSG
1659
1717
  # by calling new on the column type or aggregation type (through composed_of) object with these parameters.
1660
1718
  # So having the pairs written_on(1) = "2004", written_on(2) = "6", written_on(3) = "24", will instantiate
1661
1719
  # written_on (a date type) with Date.new("2004", "6", "24"). You can also specify a typecast character in the
1662
- # parentheses to have the parameters typecasted before they're used in the constructor. Use i for Fixnum, f for Float,
1663
- # s for String, and a for Array. If all the values for a given attribute are empty, the attribute will be set to nil.
1720
+ # parentheses to have the parameters typecasted before they're used in the constructor. Use i for Fixnum,
1721
+ # f for Float, s for String, and a for Array. If all the values for a given attribute are empty, the
1722
+ # attribute will be set to nil.
1664
1723
  def assign_multiparameter_attributes(pairs)
1665
1724
  execute_callstack_for_multiparameter_attributes(
1666
1725
  extract_callstack_for_multiparameter_attributes(pairs)
@@ -1682,7 +1741,7 @@ MSG
1682
1741
  klass = (self.class.reflect_on_aggregation(name.to_sym) || column_for_attribute(name)).klass
1683
1742
  # in order to allow a date to be set without a year, we must keep the empty values.
1684
1743
  # Otherwise, we wouldn't be able to distinguish it from a date with an empty day.
1685
- values = values_with_empty_parameters.reject(&:nil?)
1744
+ values = values_with_empty_parameters.reject { |v| v.nil? }
1686
1745
 
1687
1746
  if values.empty?
1688
1747
  send(name + "=", nil)