aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib/active_record
diff options
context:
space:
mode:
Diffstat (limited to 'activerecord/lib/active_record')
-rw-r--r--activerecord/lib/active_record/association_preload.rb4
-rwxr-xr-xactiverecord/lib/active_record/associations.rb76
-rw-r--r--activerecord/lib/active_record/associations/association_collection.rb4
-rwxr-xr-xactiverecord/lib/active_record/base.rb42
-rw-r--r--activerecord/lib/active_record/callbacks.rb18
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb8
-rw-r--r--activerecord/lib/active_record/fixtures.rb2
-rw-r--r--activerecord/lib/active_record/migration.rb6
-rw-r--r--activerecord/lib/active_record/nested_attributes.rb2
-rw-r--r--activerecord/lib/active_record/validations.rb2
11 files changed, 146 insertions, 20 deletions
diff --git a/activerecord/lib/active_record/association_preload.rb b/activerecord/lib/active_record/association_preload.rb
index af80a579d6..e41fda7a4b 100644
--- a/activerecord/lib/active_record/association_preload.rb
+++ b/activerecord/lib/active_record/association_preload.rb
@@ -28,7 +28,7 @@ module ActiveRecord
# 'books' table is useful; the joined 'authors' data is just redundant, and
# processing this redundant data takes memory and CPU time. The problem
# quickly becomes worse and worse as the level of eager loading increases
- # (i.e. if ActiveRecord is to eager load the associations' assocations as
+ # (i.e. if ActiveRecord is to eager load the associations' associations as
# well).
#
# The second strategy is to use multiple database queries, one for each
@@ -58,7 +58,7 @@ module ActiveRecord
# +associations+ specifies one or more associations that you want to
# preload. It may be:
# - a Symbol or a String which specifies a single association name. For
- # example, specifiying +:books+ allows this method to preload all books
+ # example, specifying +:books+ allows this method to preload all books
# for an Author.
# - an Array which specifies multiple association names. This array
# is processed recursively. For example, specifying <tt>[:avatar, :books]</tt>
diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb
index 934beb7d39..66aa9332c8 100755
--- a/activerecord/lib/active_record/associations.rb
+++ b/activerecord/lib/active_record/associations.rb
@@ -519,13 +519,13 @@ module ActiveRecord
#
# Post.find(:all, :include => [ :author, :comments ], :conditions => ['comments.approved = ?', true])
#
- # will result in a single SQL query with joins along the lines of: <tt>LEFT OUTER JOIN comments ON comments.post_id = posts.id</tt> and
+ # This will result in a single SQL query with joins along the lines of: <tt>LEFT OUTER JOIN comments ON comments.post_id = posts.id</tt> and
# <tt>LEFT OUTER JOIN authors ON authors.id = posts.author_id</tt>. Note that using conditions like this can have unintended consequences.
# In the above example posts with no approved comments are not returned at all, because the conditions apply to the SQL statement as a whole
# and not just to the association. You must disambiguate column references for this fallback to happen, for example
# <tt>:order => "author.name DESC"</tt> will work but <tt>:order => "name DESC"</tt> will not.
#
- # If you do want eagerload only some members of an association it is usually more natural to <tt>:include</tt> an association
+ # If you do want eager load only some members of an association it is usually more natural to <tt>:include</tt> an association
# which has conditions defined on it:
#
# class Post < ActiveRecord::Base
@@ -534,7 +534,7 @@ module ActiveRecord
#
# Post.find(:all, :include => :approved_comments)
#
- # will load posts and eager load the +approved_comments+ association, which contains only those comments that have been approved.
+ # This will load posts and eager load the +approved_comments+ association, which contains only those comments that have been approved.
#
# If you eager load an association with a specified <tt>:limit</tt> option, it will be ignored, returning all the associated objects:
#
@@ -557,7 +557,7 @@ module ActiveRecord
#
# Address.find(:all, :include => :addressable)
#
- # will execute one query to load the addresses and load the addressables with one query per addressable type.
+ # This will execute one query to load the addresses and load the addressables with one query per addressable type.
# For example if all the addressables are either of class Person or Company then a total of 3 queries will be executed. The list of
# addressable types to load is determined on the back of the addresses loaded. This is not supported if Active Record has to fallback
# to the previous implementation of eager loading and will raise ActiveRecord::EagerLoadPolymorphicError. The reason is that the parent
@@ -641,6 +641,60 @@ module ActiveRecord
# end
# end
#
+ # == Bi-directional associations
+ #
+ # When you specify an association there is usually an association on the associated model that specifies the same
+ # relationship in reverse. For example, with the following models:
+ #
+ # class Dungeon < ActiveRecord::Base
+ # has_many :traps
+ # has_one :evil_wizard
+ # end
+ #
+ # class Trap < ActiveRecord::Base
+ # belongs_to :dungeon
+ # end
+ #
+ # class EvilWizard < ActiveRecord::Base
+ # belongs_to :dungeon
+ # end
+ #
+ # The +traps+ association on +Dungeon+ and the the +dungeon+ association on +Trap+ are the inverse of each other and the
+ # inverse of the +dungeon+ association on +EvilWizard+ is the +evil_wizard+ association on +Dungeon+ (and vice-versa). By default,
+ # +ActiveRecord+ doesn't do know anything about these inverse relationships and so no object loading optimisation is possible. For example:
+ #
+ # d = Dungeon.first
+ # t = d.traps.first
+ # d.level == t.dungeon.level # => true
+ # d.level = 10
+ # d.level == t.dungeon.level # => false
+ #
+ # The +Dungeon+ instances +d+ and <tt>t.dungeon</tt> in the above example refer to the same object data from the database, but are
+ # actually different in-memory copies of that data. Specifying the <tt>:inverse_of</tt> option on associations lets you tell
+ # +ActiveRecord+ about inverse relationships and it will optimise object loading. For example, if we changed our model definitions to:
+ #
+ # class Dungeon < ActiveRecord::Base
+ # has_many :traps, :inverse_of => :dungeon
+ # has_one :evil_wizard, :inverse_of => :dungeon
+ # end
+ #
+ # class Trap < ActiveRecord::Base
+ # belongs_to :dungeon, :inverse_of => :traps
+ # end
+ #
+ # class EvilWizard < ActiveRecord::Base
+ # belongs_to :dungeon, :inverse_of => :evil_wizard
+ # end
+ #
+ # Then, from our code snippet above, +d+ and <tt>t.dungeon</tt> are actually the same in-memory instance and our final <tt>d.level == t.dungeon.level</tt>
+ # will return +true+.
+ #
+ # There are limitations to <tt>:inverse_of</tt> support:
+ #
+ # * does not work with <tt>:through</tt> associations.
+ # * does not work with <tt>:polymorphic</tt> associations.
+ # * for +belongs_to+ associations +has_many+ inverse associations are ignored.
+ #
# == Type safety with <tt>ActiveRecord::AssociationTypeMismatch</tt>
#
# If you attempt to assign an object to an association that doesn't match the inferred or specified <tt>:class_name</tt>, you'll
@@ -781,6 +835,10 @@ module ActiveRecord
# If false, don't validate the associated objects when saving the parent object. true by default.
# [:autosave]
# If true, always save any loaded members and destroy members marked for destruction, when saving the parent object. Off by default.
+ # [:inverse_of]
+ # Specifies the name of the <tt>belongs_to</tt> association on the associated object that is the inverse of this <tt>has_many</tt>
+ # association. Does not work in combination with <tt>:through</tt> or <tt>:as</tt> options.
+ # See ActiveRecord::Associations::ClassMethods's overview on Bi-directional assocations for more detail.
#
# Option examples:
# has_many :comments, :order => "posted_on"
@@ -890,6 +948,10 @@ module ActiveRecord
# If false, don't validate the associated object when saving the parent object. +false+ by default.
# [:autosave]
# If true, always save the associated object or destroy it if marked for destruction, when saving the parent object. Off by default.
+ # [:inverse_of]
+ # Specifies the name of the <tt>belongs_to</tt> association on the associated object that is the inverse of this <tt>has_one</tt>
+ # association. Does not work in combination with <tt>:through</tt> or <tt>:as</tt> options.
+ # See ActiveRecord::Associations::ClassMethods's overview on Bi-directional assocations for more detail.
#
# Option examples:
# has_one :credit_card, :dependent => :destroy # destroys the associated credit card
@@ -992,6 +1054,10 @@ module ActiveRecord
# [:touch]
# If true, the associated object will be touched (the updated_at/on attributes set to now) when this record is either saved or
# destroyed. If you specify a symbol, that attribute will be updated with the current time instead of the updated_at/on attribute.
+ # [:inverse_of]
+ # Specifies the name of the <tt>has_one</tt> or <tt>has_many</tt> association on the associated object that is the inverse of this <tt>belongs_to</tt>
+ # association. Does not work in combination with the <tt>:polymorphic</tt> options.
+ # See ActiveRecord::Associations::ClassMethods's overview on Bi-directional assocations for more detail.
#
# Option examples:
# belongs_to :firm, :foreign_key => "client_of"
@@ -1201,7 +1267,7 @@ module ActiveRecord
private
# Generates a join table name from two provided table names.
- # The names in the join table namesme end up in lexicographic order.
+ # The names in the join table names end up in lexicographic order.
#
# join_table_name("members", "clubs") # => "clubs_members"
# join_table_name("members", "special_clubs") # => "members_special_clubs"
diff --git a/activerecord/lib/active_record/associations/association_collection.rb b/activerecord/lib/active_record/associations/association_collection.rb
index 84edaec15e..e67ccfb228 100644
--- a/activerecord/lib/active_record/associations/association_collection.rb
+++ b/activerecord/lib/active_record/associations/association_collection.rb
@@ -11,7 +11,7 @@ module ActiveRecord
# ones created with +build+ are added to the target. So, the target may be
# non-empty and still lack children waiting to be read from the database.
# If you look directly to the database you cannot assume that's the entire
- # collection because new records may have beed added to the target, etc.
+ # collection because new records may have been added to the target, etc.
#
# If you need to work on all current children, new and existing records,
# +load_target+ and the +loaded+ flag are your friends.
@@ -228,7 +228,7 @@ module ActiveRecord
self
end
- # Destory all the records from this association.
+ # Destroy all the records from this association.
#
# See destroy for more info.
def destroy_all
diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb
index 62e97158ec..5a36ff5ba2 100755
--- a/activerecord/lib/active_record/base.rb
+++ b/activerecord/lib/active_record/base.rb
@@ -256,6 +256,12 @@ module ActiveRecord #:nodoc:
#
# Student.find(:all, :conditions => { :grade => [9,11,12] })
#
+ # 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
+ # particular condition. For instance:
+ #
+ # Student.find(:all, :conditions => { :schools => { :type => 'public' }}, :joins => :schools)
+ # Student.find(:all, :conditions => { 'schools.type' => 'public' }, :joins => :schools)
+ #
# == Overwriting default accessors
#
# All column values are automatically available through basic accessors on the Active Record object, but sometimes you
@@ -854,7 +860,7 @@ module ActiveRecord #:nodoc:
# Book.update_all "author = 'David'", "title LIKE '%Rails%'"
#
# # Update all avatars migrated more than a week ago
- # Avatar.update_all ['migrated_at = ?, Time.now.utc], ['migrated_at > ?', 1.week.ago]
+ # Avatar.update_all ['migrated_at = ?', Time.now.utc], ['migrated_at > ?', 1.week.ago]
#
# # Update all books that match our conditions, but limit it to 5 ordered by date
# Book.update_all "author = 'David'", "title LIKE '%Rails%'", :order => 'created_at', :limit => 5
@@ -1055,6 +1061,21 @@ module ActiveRecord #:nodoc:
#
# To start from an all-closed default and enable attributes as needed,
# have a look at +attr_accessible+.
+ #
+ # If the access logic of your application is richer you can use <tt>Hash#except</tt>
+ # or <tt>Hash#slice</tt> to sanitize the hash of parameters before they are
+ # passed to Active Record.
+ #
+ # For example, it could be the case that the list of protected attributes
+ # for a given model depends on the role of the user:
+ #
+ # # Assumes plan_id is not protected because it depends on the role.
+ # params[:account] = params[:account].except(:plan_id) unless admin?
+ # @account.update_attributes(params[:account])
+ #
+ # Note that +attr_protected+ is still applied to the received hash. Thus,
+ # with this technique you can at most _extend_ the list of protected
+ # attributes for a particular mass-assignment call.
def attr_protected(*attributes)
write_inheritable_attribute(:attr_protected, Set.new(attributes.map {|a| a.to_s}) + (protected_attributes || []))
end
@@ -1088,6 +1109,21 @@ module ActiveRecord #:nodoc:
#
# customer.credit_rating = "Average"
# customer.credit_rating # => "Average"
+ #
+ # If the access logic of your application is richer you can use <tt>Hash#except</tt>
+ # or <tt>Hash#slice</tt> to sanitize the hash of parameters before they are
+ # passed to Active Record.
+ #
+ # For example, it could be the case that the list of accessible attributes
+ # for a given model depends on the role of the user:
+ #
+ # # Assumes plan_id is accessible because it depends on the role.
+ # params[:account] = params[:account].except(:plan_id) unless admin?
+ # @account.update_attributes(params[:account])
+ #
+ # Note that +attr_accessible+ is still applied to the received hash. Thus,
+ # with this technique you can at most _narrow_ the list of accessible
+ # attributes for a particular mass-assignment call.
def attr_accessible(*attributes)
write_inheritable_attribute(:attr_accessible, Set.new(attributes.map(&:to_s)) + (accessible_attributes || []))
end
@@ -1382,14 +1418,14 @@ module ActiveRecord #:nodoc:
classes
rescue
# OPTIMIZE this rescue is to fix this test: ./test/cases/reflection_test.rb:56:in `test_human_name_for_column'
- # Appearantly the method base_class causes some trouble.
+ # Apparently the method base_class causes some trouble.
# It now works for sure.
[self]
end
# Transforms attribute key names into a more humane format, such as "First name" instead of "first_name". Example:
# Person.human_attribute_name("first_name") # => "First name"
- # This used to be depricated in favor of humanize, but is now preferred, because it automatically uses the I18n
+ # This used to be deprecated in favor of humanize, but is now preferred, because it automatically uses the I18n
# module now.
# Specify +options+ with additional translating options.
def human_attribute_name(attribute_key_name, options = {})
diff --git a/activerecord/lib/active_record/callbacks.rb b/activerecord/lib/active_record/callbacks.rb
index 3aa0b8f1b5..4a2ec5bf95 100644
--- a/activerecord/lib/active_record/callbacks.rb
+++ b/activerecord/lib/active_record/callbacks.rb
@@ -22,7 +22,7 @@ module ActiveRecord
# * (8) <tt>after_save</tt>
#
# That's a total of eight callbacks, which gives you immense power to react and prepare for each state in the
- # Active Record lifecycle. The sequence for calling <tt>Base#save</tt> an existing record is similar, except that each
+ # Active Record lifecycle. The sequence for calling <tt>Base#save</tt> for an existing record is similar, except that each
# <tt>_on_create</tt> callback is replaced by the corresponding <tt>_on_update</tt> callback.
#
# Examples:
@@ -262,6 +262,10 @@ module ActiveRecord
# Is called _after_ <tt>Base.save</tt> on new objects that haven't been saved yet (no record exists).
# Note that this callback is still wrapped in the transaction around +save+. For example, if you
# invoke an external indexer at this point it won't see the changes in the database.
+ #
+ # class Contact < ActiveRecord::Base
+ # after_create { |record| logger.info( "Contact #{record.id} was created." ) }
+ # end
def after_create() end
def create_with_callbacks #:nodoc:
return false if callback(:before_create) == false
@@ -272,11 +276,19 @@ module ActiveRecord
private :create_with_callbacks
# Is called _before_ <tt>Base.save</tt> on existing objects that have a record.
+ #
+ # class Contact < ActiveRecord::Base
+ # before_update { |record| logger.info( "Contact #{record.id} is about to be updated." ) }
+ # end
def before_update() end
# Is called _after_ <tt>Base.save</tt> on existing objects that have a record.
# Note that this callback is still wrapped in the transaction around +save+. For example, if you
# invoke an external indexer at this point it won't see the changes in the database.
+ #
+ # class Contact < ActiveRecord::Base
+ # after_update { |record| logger.info( "Contact #{record.id} was updated." ) }
+ # end
def after_update() end
def update_with_callbacks(*args) #:nodoc:
@@ -326,6 +338,10 @@ module ActiveRecord
#
# Note: If you need to _destroy_ or _nullify_ associated records first,
# use the <tt>:dependent</tt> option on your associations.
+ #
+ # class Contact < ActiveRecord::Base
+ # after_destroy { |record| logger.info( "Contact #{record.id} is about to be destroyed." ) }
+ # end
def before_destroy() end
# Is called _after_ <tt>Base.destroy</tt> (and all the attributes have been frozen).
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb
index 500dafdc2e..12253eac3f 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb
@@ -362,7 +362,7 @@ module ActiveRecord
def call(env)
@app.call(env)
ensure
- # Don't return connection (and peform implicit rollback) if
+ # Don't return connection (and perform implicit rollback) if
# this request is a part of integration test
unless env.key?("rack.test")
ActiveRecord::Base.clear_active_connections!
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
index f44cd0bd5a..2473c772e3 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
@@ -41,11 +41,19 @@ module ActiveRecord
# # create_table() passes a TableDefinition object to the block.
# # This form will not only create the table, but also columns for the
# # table.
+ #
# create_table(:suppliers) do |t|
# t.column :name, :string, :limit => 60
# # Other fields here
# end
#
+ # === Block form, with shorthand
+ # # You can also use the column types as method calls, rather than calling the column method.
+ # create_table(:suppliers) do |t|
+ # t.string :name, :limit => 60
+ # # Other fields here
+ # end
+ #
# === Regular form
# # Creates a table called 'suppliers' with no columns.
# create_table(:suppliers)
diff --git a/activerecord/lib/active_record/fixtures.rb b/activerecord/lib/active_record/fixtures.rb
index 2b0cfc2c3b..6eeeddc9e1 100644
--- a/activerecord/lib/active_record/fixtures.rb
+++ b/activerecord/lib/active_record/fixtures.rb
@@ -409,7 +409,7 @@ end
# subdomain: $LABEL
#
# Also, sometimes (like when porting older join table fixtures) you'll need
-# to be able to get ahold of the identifier for a given label. ERB
+# to be able to get a hold of the identifier for a given label. ERB
# to the rescue:
#
# george_reginald:
diff --git a/activerecord/lib/active_record/migration.rb b/activerecord/lib/active_record/migration.rb
index 467d955a49..3963baa6b8 100644
--- a/activerecord/lib/active_record/migration.rb
+++ b/activerecord/lib/active_record/migration.rb
@@ -109,8 +109,8 @@ module ActiveRecord
# script/generate migration MyNewMigration
#
# where MyNewMigration is the name of your migration. The generator will
- # create an empty migration file <tt>nnn_my_new_migration.rb</tt> in the <tt>db/migrate/</tt>
- # directory where <tt>nnn</tt> is the next largest migration number.
+ # create an empty migration file <tt>timestamp_my_new_migration.rb</tt> in the <tt>db/migrate/</tt>
+ # directory where <tt>timestamp</tt> is the UTC formatted date and time that the migration was generated.
#
# You may then edit the <tt>self.up</tt> and <tt>self.down</tt> methods of
# MyNewMigration.
@@ -118,7 +118,7 @@ module ActiveRecord
# There is a special syntactic shortcut to generate migrations that add fields to a table.
# script/generate migration add_fieldname_to_tablename fieldname:string
#
- # This will generate the file <tt>nnn_add_fieldname_to_tablename</tt>, which will look like this:
+ # This will generate the file <tt>timestamp_add_fieldname_to_tablename</tt>, which will look like this:
# class AddFieldnameToTablename < ActiveRecord::Migration
# def self.up
# add_column :tablenames, :fieldname, :string
diff --git a/activerecord/lib/active_record/nested_attributes.rb b/activerecord/lib/active_record/nested_attributes.rb
index 0beb4321a2..bc4cca7855 100644
--- a/activerecord/lib/active_record/nested_attributes.rb
+++ b/activerecord/lib/active_record/nested_attributes.rb
@@ -284,7 +284,7 @@ module ActiveRecord
# })
#
# Will update the name of the Person with ID 1, build a new associated
- # person with the name `John', and mark the associatied Person with ID 2
+ # person with the name `John', and mark the associated Person with ID 2
# for destruction.
#
# Also accepts an Array of attribute hashes:
diff --git a/activerecord/lib/active_record/validations.rb b/activerecord/lib/active_record/validations.rb
index 7ac6f6fe3b..a7fa98756e 100644
--- a/activerecord/lib/active_record/validations.rb
+++ b/activerecord/lib/active_record/validations.rb
@@ -63,7 +63,7 @@ module ActiveRecord
# default message (e.g. <tt>activerecord.errors.messages.MESSAGE</tt>). The translated model name,
# translated attribute name and the value are available for interpolation.
#
- # When using inheritence in your models, it will check all the inherited models too, but only if the model itself
+ # When using inheritance in your models, it will check all the inherited models too, but only if the model itself
# hasn't been found. Say you have <tt>class Admin < User; end</tt> and you wanted the translation for the <tt>:blank</tt>
# error +message+ for the <tt>title</tt> +attribute+, it looks for these translations:
#