aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--activerecord/lib/active_record/associations.rb270
-rw-r--r--guides/source/association_basics.textile577
2 files changed, 385 insertions, 462 deletions
diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb
index 17df34ed8a..f5ee4f3ebe 100644
--- a/activerecord/lib/active_record/associations.rb
+++ b/activerecord/lib/active_record/associations.rb
@@ -195,26 +195,6 @@ module ActiveRecord
# * <tt>Project#categories.empty?, Project#categories.size, Project#categories, Project#categories<<(category1),</tt>
# <tt>Project#categories.delete(category1)</tt>
#
- # === Overriding generated methods
- #
- # Association methods are generated in a module that is included into the model class,
- # which allows you to easily override with your own methods and call the original
- # generated method with +super+. For example:
- #
- # class Car < ActiveRecord::Base
- # belongs_to :owner
- # belongs_to :old_owner
- # def owner=(new_owner)
- # self.old_owner = self.owner
- # super
- # end
- # end
- #
- # If your model class is <tt>Project</tt>, the module is
- # named <tt>Project::GeneratedFeatureMethods</tt>. The GeneratedFeatureMethods module is
- # included in the model class immediately after the (anonymous) generated attributes methods
- # module, meaning an association will override the methods for an attribute with the same name.
- #
# === A word of warning
#
# Don't create associations that have the same name as instance methods of
@@ -262,6 +242,26 @@ module ActiveRecord
# others.uniq | X | X | X
# others.reset | X | X | X
#
+ # === Overriding generated methods
+ #
+ # Association methods are generated in a module that is included into the model class,
+ # which allows you to easily override with your own methods and call the original
+ # generated method with +super+. For example:
+ #
+ # class Car < ActiveRecord::Base
+ # belongs_to :owner
+ # belongs_to :old_owner
+ # def owner=(new_owner)
+ # self.old_owner = self.owner
+ # super
+ # end
+ # end
+ #
+ # If your model class is <tt>Project</tt>, the module is
+ # named <tt>Project::GeneratedFeatureMethods</tt>. The GeneratedFeatureMethods module is
+ # included in the model class immediately after the (anonymous) generated attributes methods
+ # module, meaning an association will override the methods for an attribute with the same name.
+ #
# == Cardinality and associations
#
# Active Record associations can be used to describe one-to-one, one-to-many and many-to-many
@@ -397,7 +397,28 @@ module ActiveRecord
# * All unsaved (<tt>new_record? == true</tt>) members of the collection are automatically
# saved when the parent is saved.
#
- # === Association callbacks
+ # == Customizing the query
+ #
+ # Associations are built from <tt>Relation</tt>s, and you can use the <tt>Relation</tt> syntax
+ # to customize them. For example, to add a condition:
+ #
+ # class Blog < ActiveRecord::Base
+ # has_many :published_posts, -> { where published: true }, class_name: 'Post'
+ # end
+ #
+ # Inside the <tt>-> { ... }</tt> block you can use all of the usual <tt>Relation</tt> methods.
+ #
+ # === Accessing the owner object
+ #
+ # Sometimes it is useful to have access to the owner object when building the query. The owner
+ # is passed as a parameter to the block. For example, the following association would find all
+ # events that occur on the user's birthday:
+ #
+ # class User < ActiveRecord::Base
+ # has_many :birthday_events, ->(user) { where starts_on: user.birthday }, class_name: 'Event'
+ # end
+ #
+ # == Association callbacks
#
# Similar to the normal callbacks that hook into the life cycle of an Active Record object,
# you can also define callbacks that get triggered when you add an object to or remove an
@@ -424,7 +445,7 @@ module ActiveRecord
# added to the collection. Same with the +before_remove+ callbacks; if an exception is
# thrown the object doesn't get removed.
#
- # === Association extensions
+ # == Association extensions
#
# The proxy objects that control the access to associations can be extended through anonymous
# modules. This is especially beneficial for adding new finders, creators, and other
@@ -454,20 +475,11 @@ module ActiveRecord
# end
#
# class Account < ActiveRecord::Base
- # has_many :people, :extend => FindOrCreateByNameExtension
+ # has_many :people, -> { extending FindOrCreateByNameExtension }
# end
#
# class Company < ActiveRecord::Base
- # has_many :people, :extend => FindOrCreateByNameExtension
- # end
- #
- # If you need to use multiple named extension modules, you can specify an array of modules
- # with the <tt>:extend</tt> option.
- # In the case of name conflicts between methods in the modules, methods in modules later
- # in the array supercede those earlier in the array.
- #
- # class Account < ActiveRecord::Base
- # has_many :people, :extend => [FindOrCreateByNameExtension, FindRecentExtension]
+ # has_many :people, -> { extending FindOrCreateByNameExtension }
# end
#
# Some extensions can only be made to work with knowledge of the association's internals.
@@ -485,7 +497,7 @@ module ActiveRecord
# the same object, allowing you to make calls like <tt>proxy_association.owner</tt> inside
# association extensions.
#
- # === Association Join Models
+ # == Association Join Models
#
# Has Many associations can be configured with the <tt>:through</tt> option to use an
# explicit join model to retrieve the data. This operates similarly to a
@@ -569,7 +581,7 @@ module ActiveRecord
# belongs_to :tag, :inverse_of => :taggings
# end
#
- # === Nested Associations
+ # == Nested Associations
#
# You can actually specify *any* association with the <tt>:through</tt> option, including an
# association which has a <tt>:through</tt> option itself. For example:
@@ -612,7 +624,7 @@ module ActiveRecord
# add a <tt>Commenter</tt> in the example above, there would be no way to tell how to set up the
# intermediate <tt>Post</tt> and <tt>Comment</tt> objects.
#
- # === Polymorphic Associations
+ # == Polymorphic Associations
#
# Polymorphic associations on models are not restricted on what types of models they
# can be associated with. Rather, they specify an interface that a +has_many+ association
@@ -742,7 +754,7 @@ module ActiveRecord
# to include an association which has conditions defined on it:
#
# class Post < ActiveRecord::Base
- # has_many :approved_comments, :class_name => 'Comment', :conditions => ['approved = ?', true]
+ # has_many :approved_comments, -> { where approved: true }, :class_name => 'Comment'
# end
#
# Post.includes(:approved_comments)
@@ -754,14 +766,11 @@ module ActiveRecord
# returning all the associated objects:
#
# class Picture < ActiveRecord::Base
- # has_many :most_recent_comments, :class_name => 'Comment', :order => 'id DESC', :limit => 10
+ # has_many :most_recent_comments, -> { order('id DESC').limit(10) }, :class_name => 'Comment'
# end
#
# Picture.includes(:most_recent_comments).first.most_recent_comments # => returns all associated comments.
#
- # When eager loaded, conditions are interpolated in the context of the model class, not
- # the model instance. Conditions are lazily interpolated before the actual model exists.
- #
# Eager loading is supported with polymorphic associations.
#
# class Address < ActiveRecord::Base
@@ -839,8 +848,8 @@ module ActiveRecord
# module MyApplication
# module Business
# class Firm < ActiveRecord::Base
- # has_many :clients
- # end
+ # has_many :clients
+ # end
#
# class Client < ActiveRecord::Base; end
# end
@@ -1078,15 +1087,6 @@ module ActiveRecord
# from the association name. So <tt>has_many :products</tt> will by default be linked
# to the Product class, but if the real class name is SpecialProduct, you'll have to
# specify it with this option.
- # [:conditions]
- # Specify the conditions that the associated objects must meet in order to be included as a +WHERE+
- # SQL fragment, such as <tt>price > 5 AND name LIKE 'B%'</tt>. Record creations from
- # the association are scoped if a hash is used.
- # <tt>has_many :posts, :conditions => {:published => true}</tt> will create published
- # posts with <tt>@blog.posts.create</tt> or <tt>@blog.posts.build</tt>.
- # [:order]
- # Specify the order in which the associated objects are returned as an <tt>ORDER BY</tt> SQL fragment,
- # such as <tt>last_name, first_name DESC</tt>.
# [:foreign_key]
# Specify the foreign key used for the association. By default this is guessed to be the name
# of this class in lower-case and "_id" suffixed. So a Person class that makes a +has_many+
@@ -1104,34 +1104,6 @@ module ActiveRecord
# If using with the <tt>:through</tt> option, the association on the join model must be
# a +belongs_to+, and the records which get deleted are the join records, rather than
# the associated records.
- #
- # [:finder_sql]
- # Specify a complete SQL statement to fetch the association. This is a good way to go for complex
- # associations that depend on multiple tables. May be supplied as a string or a proc where interpolation is
- # required. Note: When this option is used, +find_in_collection+
- # is _not_ added.
- # [:counter_sql]
- # Specify a complete SQL statement to fetch the size of the association. If <tt>:finder_sql</tt> is
- # specified but not <tt>:counter_sql</tt>, <tt>:counter_sql</tt> will be generated by
- # replacing <tt>SELECT ... FROM</tt> with <tt>SELECT COUNT(*) FROM</tt>.
- # [:extend]
- # Specify a named module for extending the proxy. See "Association extensions".
- # [:include]
- # Specify second-order associations that should be eager loaded when the collection is loaded.
- # [:group]
- # An attribute name by which the result should be grouped. Uses the <tt>GROUP BY</tt> SQL-clause.
- # [:having]
- # Combined with +:group+ this can be used to filter the records that a <tt>GROUP BY</tt>
- # returns. Uses the <tt>HAVING</tt> SQL-clause.
- # [:limit]
- # An integer determining the limit on the number of rows that should be returned.
- # [:offset]
- # An integer determining the offset from where the rows should be fetched. So at 5,
- # it would skip the first 4 rows.
- # [:select]
- # By default, this is <tt>*</tt> as in <tt>SELECT * FROM</tt>, but can be changed if
- # you want to do a join but not include the joined columns, for example. Do not forget
- # to include the primary and foreign keys, otherwise it will raise an error.
# [:as]
# Specifies a polymorphic interface (See <tt>belongs_to</tt>).
# [:through]
@@ -1158,10 +1130,6 @@ module ActiveRecord
# [:source_type]
# Specifies type of the source association used by <tt>has_many :through</tt> queries where the source
# association is a polymorphic +belongs_to+.
- # [:uniq]
- # If true, duplicates will be omitted from the collection. Useful in conjunction with <tt>:through</tt>.
- # [:readonly]
- # If true, all the associated objects are readonly through the association.
# [:validate]
# If +false+, don't validate the associated objects when saving the parent object. true by default.
# [:autosave]
@@ -1177,22 +1145,14 @@ module ActiveRecord
# See ActiveRecord::Associations::ClassMethods's overview on Bi-directional associations for more detail.
#
# Option examples:
- # has_many :comments, :order => "posted_on"
- # has_many :comments, :include => :author
- # has_many :people, :class_name => "Person", :conditions => "deleted = 0", :order => "name"
- # has_many :tracks, :order => "position", :dependent => :destroy
- # has_many :comments, :dependent => :nullify
- # has_many :tags, :as => :taggable
- # has_many :reports, :readonly => true
- # has_many :subscribers, :through => :subscriptions, :source => :user
- # has_many :subscribers, :class_name => "Person", :finder_sql => Proc.new {
- # %Q{
- # SELECT DISTINCT *
- # FROM people p, post_subscriptions ps
- # WHERE ps.post_id = #{id} AND ps.person_id = p.id
- # ORDER BY p.first_name
- # }
- # }
+ # has_many :comments, -> { order "posted_on" }
+ # has_many :comments, -> { includes :author }
+ # has_many :people, -> { where("deleted = 0").order("name") }, class_name: "Person"
+ # has_many :tracks, -> { order "position" }, dependent: :destroy
+ # has_many :comments, dependent: :nullify
+ # has_many :tags, as: :taggable
+ # has_many :reports, -> { readonly }
+ # has_many :subscribers, through: :subscriptions, source: :user
def has_many(name, scope = nil, options = {}, &extension)
Builder::HasMany.build(self, name, scope, options, &extension)
end
@@ -1242,14 +1202,6 @@ module ActiveRecord
# Specify the class name of the association. Use it only if that name can't be inferred
# from the association name. So <tt>has_one :manager</tt> will by default be linked to the Manager class, but
# if the real class name is Person, you'll have to specify it with this option.
- # [:conditions]
- # Specify the conditions that the associated object must meet in order to be included as a +WHERE+
- # SQL fragment, such as <tt>rank = 5</tt>. Record creation from the association is scoped if a hash
- # is used. <tt>has_one :account, :conditions => {:enabled => true}</tt> will create
- # an enabled account with <tt>@company.create_account</tt> or <tt>@company.build_account</tt>.
- # [:order]
- # Specify the order in which the associated objects are returned as an <tt>ORDER BY</tt> SQL fragment,
- # such as <tt>last_name, first_name DESC</tt>.
# [:dependent]
# If set to <tt>:destroy</tt>, the associated object is destroyed when this object is. If set to
# <tt>:delete</tt>, the associated object is deleted *without* calling its destroy method.
@@ -1262,14 +1214,8 @@ module ActiveRecord
# will use "person_id" as the default <tt>:foreign_key</tt>.
# [:primary_key]
# Specify the method that returns the primary key used for the association. By default this is +id+.
- # [:include]
- # Specify second-order associations that should be eager loaded when this object is loaded.
# [:as]
# Specifies a polymorphic interface (See <tt>belongs_to</tt>).
- # [:select]
- # By default, this is <tt>*</tt> as in <tt>SELECT * FROM</tt>, but can be changed if
- # you want to do a join but not include the joined columns, for example. Do not forget to include the
- # primary and foreign keys, otherwise it will raise an error.
# [:through]
# Specifies a Join Model through which to perform the query. Options for <tt>:class_name</tt>,
# <tt>:primary_key</tt>, and <tt>:foreign_key</tt> are ignored, as the association uses the
@@ -1283,8 +1229,6 @@ module ActiveRecord
# [:source_type]
# Specifies type of the source association used by <tt>has_one :through</tt> queries where the source
# association is a polymorphic +belongs_to+.
- # [:readonly]
- # If true, the associated object is readonly through the association.
# [:validate]
# If +false+, don't validate the associated object when saving the parent object. +false+ by default.
# [:autosave]
@@ -1303,12 +1247,12 @@ module ActiveRecord
# has_one :credit_card, :dependent => :destroy # destroys the associated credit card
# has_one :credit_card, :dependent => :nullify # updates the associated records foreign
# # key value to NULL rather than destroying it
- # has_one :last_comment, :class_name => "Comment", :order => "posted_on"
- # has_one :project_manager, :class_name => "Person", :conditions => "role = 'project_manager'"
- # has_one :attachment, :as => :attachable
- # has_one :boss, :readonly => :true
- # has_one :club, :through => :membership
- # has_one :primary_address, :through => :addressables, :conditions => ["addressable.primary = ?", true], :source => :addressable
+ # has_one :last_comment, -> { order 'posted_on' }, :class_name => "Comment"
+ # has_one :project_manager, -> { where role: 'project_manager' }, :class_name => "Person"
+ # has_one :attachment, as: :attachable
+ # has_one :boss, readonly: :true
+ # has_one :club, through: :membership
+ # has_one :primary_address, -> { where primary: true }, through: :addressables, source: :addressable
def has_one(name, scope = nil, options = {})
Builder::HasOne.build(self, name, scope, options)
end
@@ -1355,13 +1299,6 @@ module ActiveRecord
# Specify the class name of the association. Use it only if that name can't be inferred
# from the association name. So <tt>belongs_to :author</tt> will by default be linked to the Author class, but
# if the real class name is Person, you'll have to specify it with this option.
- # [:conditions]
- # Specify the conditions that the associated object must meet in order to be included as a +WHERE+
- # SQL fragment, such as <tt>authorized = 1</tt>.
- # [:select]
- # By default, this is <tt>*</tt> as in <tt>SELECT * FROM</tt>, but can be changed
- # if you want to do a join but not include the joined columns, for example. Do not
- # forget to include the primary and foreign keys, otherwise it will raise an error.
# [:foreign_key]
# Specify the foreign key used for the association. By default this is guessed to be the name
# of the association with an "_id" suffix. So a class that defines a <tt>belongs_to :person</tt>
@@ -1394,14 +1331,10 @@ module ActiveRecord
# option (e.g., <tt>:counter_cache => :my_custom_counter</tt>.)
# Note: Specifying a counter cache will add it to that model's list of readonly attributes
# using +attr_readonly+.
- # [:include]
- # Specify second-order associations that should be eager loaded when this object is loaded.
# [:polymorphic]
# Specify this association is a polymorphic association by passing +true+.
# Note: If you've enabled the counter cache, then you may want to add the counter cache attribute
# to the +attr_readonly+ list in the associated classes (e.g. <tt>class Post; attr_readonly :comments_count; end</tt>).
- # [:readonly]
- # If true, the associated object is readonly through the association.
# [:validate]
# If +false+, don't validate the associated objects when saving the parent object. +false+ by default.
# [:autosave]
@@ -1422,16 +1355,16 @@ module ActiveRecord
# See ActiveRecord::Associations::ClassMethods's overview on Bi-directional associations for more detail.
#
# Option examples:
- # belongs_to :firm, :foreign_key => "client_of"
- # belongs_to :person, :primary_key => "name", :foreign_key => "person_name"
- # belongs_to :author, :class_name => "Person", :foreign_key => "author_id"
- # belongs_to :valid_coupon, :class_name => "Coupon", :foreign_key => "coupon_id",
- # :conditions => 'discounts > #{payments_count}'
- # belongs_to :attachable, :polymorphic => true
- # belongs_to :project, :readonly => true
- # belongs_to :post, :counter_cache => true
- # belongs_to :company, :touch => true
- # belongs_to :company, :touch => :employees_last_updated_at
+ # belongs_to :firm, foreign_key: "client_of"
+ # belongs_to :person, primary_key: "name", foreign_key: "person_name"
+ # belongs_to :author, class_name: "Person", foreign_key: "author_id"
+ # belongs_to :valid_coupon, ->(o) { where "discounts > #{o.payments_count}" },
+ # class_name: "Coupon", foreign_key: "coupon_id"
+ # belongs_to :attachable, polymorphic: true
+ # belongs_to :project, readonly: true
+ # belongs_to :post, counter_cache: true
+ # belongs_to :company, touch: true
+ # belongs_to :company, touch: :employees_last_updated_at
def belongs_to(name, scope = nil, options = {})
Builder::BelongsTo.build(self, name, scope, options)
end
@@ -1545,47 +1478,6 @@ module ActiveRecord
# By default this is guessed to be the name of the associated class in lower-case and "_id" suffixed.
# So if a Person class makes a +has_and_belongs_to_many+ association to Project,
# the association will use "project_id" as the default <tt>:association_foreign_key</tt>.
- # [:conditions]
- # Specify the conditions that the associated object must meet in order to be included as a +WHERE+
- # SQL fragment, such as <tt>authorized = 1</tt>. Record creations from the association are
- # scoped if a hash is used.
- # <tt>has_many :posts, :conditions => {:published => true}</tt> will create published posts with <tt>@blog.posts.create</tt>
- # or <tt>@blog.posts.build</tt>.
- # [:order]
- # Specify the order in which the associated objects are returned as an <tt>ORDER BY</tt> SQL fragment,
- # such as <tt>last_name, first_name DESC</tt>
- # [:uniq]
- # If true, duplicate associated objects will be ignored by accessors and query methods.
- # [:finder_sql]
- # Overwrite the default generated SQL statement used to fetch the association with a manual statement
- # [:counter_sql]
- # Specify a complete SQL statement to fetch the size of the association. If <tt>:finder_sql</tt> is
- # specified but not <tt>:counter_sql</tt>, <tt>:counter_sql</tt> will be generated by
- # replacing <tt>SELECT ... FROM</tt> with <tt>SELECT COUNT(*) FROM</tt>.
- # [:delete_sql]
- # Overwrite the default generated SQL statement used to remove links between the associated
- # classes with a manual statement.
- # [:insert_sql]
- # Overwrite the default generated SQL statement used to add links between the associated classes
- # with a manual statement.
- # [:extend]
- # Anonymous module for extending the proxy, see "Association extensions".
- # [:include]
- # Specify second-order associations that should be eager loaded when the collection is loaded.
- # [:group]
- # An attribute name by which the result should be grouped. Uses the <tt>GROUP BY</tt> SQL-clause.
- # [:having]
- # Combined with +:group+ this can be used to filter the records that a <tt>GROUP BY</tt> returns.
- # Uses the <tt>HAVING</tt> SQL-clause.
- # [:limit]
- # An integer determining the limit on the number of rows that should be returned.
- # [:offset]
- # An integer determining the offset from where the rows should be fetched. So at 5,
- # it would skip the first 4 rows.
- # [:select]
- # By default, this is <tt>*</tt> as in <tt>SELECT * FROM</tt>, but can be changed if
- # you want to do a join but exclude the joined columns, for example. Do not forget to include the primary
- # and foreign keys, otherwise it will raise an error.
# [:readonly]
# If true, all the associated objects are readonly through the association.
# [:validate]
@@ -1600,12 +1492,10 @@ module ActiveRecord
#
# Option examples:
# has_and_belongs_to_many :projects
- # has_and_belongs_to_many :projects, :include => [ :milestones, :manager ]
- # has_and_belongs_to_many :nations, :class_name => "Country"
- # has_and_belongs_to_many :categories, :join_table => "prods_cats"
- # has_and_belongs_to_many :categories, :readonly => true
- # has_and_belongs_to_many :active_projects, :join_table => 'developers_projects', :delete_sql =>
- # proc { |record| "DELETE FROM developers_projects WHERE active=1 AND developer_id = #{id} AND project_id = #{record.id}" }
+ # has_and_belongs_to_many :projects, -> { includes :milestones, :manager }
+ # has_and_belongs_to_many :nations, class_name: "Country"
+ # has_and_belongs_to_many :categories, join_table: "prods_cats"
+ # has_and_belongs_to_many :categories, -> { readonly }
def has_and_belongs_to_many(name, scope = nil, options = {}, &extension)
Builder::HasAndBelongsToMany.build(self, name, scope, options, &extension)
end
diff --git a/guides/source/association_basics.textile b/guides/source/association_basics.textile
index 4dca7a508c..2b8b1bd937 100644
--- a/guides/source/association_basics.textile
+++ b/guides/source/association_basics.textile
@@ -630,12 +630,12 @@ The <tt>create_<em>association</em></tt> method returns a new object of the asso
h5. Options for +belongs_to+
-While Rails uses intelligent defaults that will work well in most situations, there may be times when you want to customize the behavior of the +belongs_to+ association reference. Such customizations can easily be accomplished by passing options when you create the association. For example, this assocation uses two such options:
+While Rails uses intelligent defaults that will work well in most situations, there may be times when you want to customize the behavior of the +belongs_to+ association reference. Such customizations can easily be accomplished by passing options and scope blocks when you create the association. For example, this assocation uses two such options:
<ruby>
class Order < ActiveRecord::Base
- belongs_to :customer, :counter_cache => true,
- :conditions => "active = 1"
+ belongs_to :customer, :dependent => :destroy,
+ :counter_cache => true
end
</ruby>
@@ -643,15 +643,11 @@ The +belongs_to+ association supports these options:
* +:autosave+
* +:class_name+
-* +:conditions+
* +:counter_cache+
* +:dependent+
* +:foreign_key+
-* +:include+
* +:inverse_of+
* +:polymorphic+
-* +:readonly+
-* +:select+
* +:touch+
* +:validate+
@@ -669,16 +665,6 @@ class Order < ActiveRecord::Base
end
</ruby>
-h6(#belongs_to-conditions). +:conditions+
-
-The +:conditions+ option lets you specify the conditions that the associated object must meet (in the syntax used by an SQL +WHERE+ clause).
-
-<ruby>
-class Order < ActiveRecord::Base
- belongs_to :customer, :conditions => "active = 1"
-end
-</ruby>
-
h6(#belongs_to-counter_cache). +:counter_cache+
The +:counter_cache+ option can be used to make finding the number of belonging objects more efficient. Consider these models:
@@ -737,35 +723,31 @@ end
TIP: In any case, Rails will not create foreign key columns for you. You need to explicitly define them as part of your migrations.
-h6(#belongs_to-includes). +:include+
+h6(#belongs_to-inverse_of). +:inverse_of+
-You can use the +:include+ option to specify second-order associations that should be eager-loaded when this association is used. For example, consider these models:
+The +:inverse_of+ option specifies the name of the +has_many+ or +has_one+ association that is the inverse of this association. Does not work in combination with the +:polymorphic+ options.
<ruby>
-class LineItem < ActiveRecord::Base
- belongs_to :order
+class Customer < ActiveRecord::Base
+ has_many :orders, :inverse_of => :customer
end
class Order < ActiveRecord::Base
- belongs_to :customer
- has_many :line_items
-end
-
-class Customer < ActiveRecord::Base
- has_many :orders
+ belongs_to :customer, :inverse_of => :orders
end
</ruby>
-If you frequently retrieve customers directly from line items (+@line_item.order.customer+), then you can make your code somewhat more efficient by including customers in the association from line items to orders:
+h6(#belongs_to-polymorphic). +:polymorphic+
-<ruby>
-class LineItem < ActiveRecord::Base
- belongs_to :order, :include => :customer
-end
+Passing +true+ to the +:polymorphic+ option indicates that this is a polymorphic association. Polymorphic associations were discussed in detail <a href="#polymorphic-associations">earlier in this guide</a>.
+h6(#belongs_to-touch). +:touch+
+
+If you set the +:touch+ option to +:true+, then the +updated_at+ or +updated_on+ timestamp on the associated object will be set to the current time whenever this object is saved or destroyed:
+
+<ruby>
class Order < ActiveRecord::Base
- belongs_to :customer
- has_many :line_items
+ belongs_to :customer, :touch => true
end
class Customer < ActiveRecord::Base
@@ -773,43 +755,58 @@ class Customer < ActiveRecord::Base
end
</ruby>
-NOTE: There's no need to use +:include+ for immediate associations - that is, if you have +Order belongs_to :customer+, then the customer is eager-loaded automatically when it's needed.
-
-h6(#belongs_to-inverse_of). +:inverse_of+
-
-The +:inverse_of+ option specifies the name of the +has_many+ or +has_one+ association that is the inverse of this association. Does not work in combination with the +:polymorphic+ options.
+In this case, saving or destroying an order will update the timestamp on the associated customer. You can also specify a particular timestamp attribute to update:
<ruby>
-class Customer < ActiveRecord::Base
- has_many :orders, :inverse_of => :customer
-end
-
class Order < ActiveRecord::Base
- belongs_to :customer, :inverse_of => :orders
+ belongs_to :customer, :touch => :orders_updated_at
end
</ruby>
-h6(#belongs_to-polymorphic). +:polymorphic+
+h6(#belongs_to-validate). +:validate+
-Passing +true+ to the +:polymorphic+ option indicates that this is a polymorphic association. Polymorphic associations were discussed in detail <a href="#polymorphic-associations">earlier in this guide</a>.
+If you set the +:validate+ option to +true+, then associated objects will be validated whenever you save this object. By default, this is +false+: associated objects will not be validated when this object is saved.
-h6(#belongs_to-readonly). +:readonly+
+h5(#belongs_to-scopes_for_belongs_to). Scopes for +belongs_to+
-If you set the +:readonly+ option to +true+, then the associated object will be read-only when retrieved via the association.
+There may be times when you wish to customize the query used by +belongs_to+. Such customizations can be achieved via a scope block. For example:
-h6(#belongs_to-select). +:select+
+<ruby>
+class Order < ActiveRecord::Base
+ belongs_to :customer, -> { where :active => true },
+ :dependent => :destroy
+end
+</ruby>
-The +:select+ option lets you override the SQL +SELECT+ clause that is used to retrieve data about the associated object. By default, Rails retrieves all columns.
+You can use any of the standard "querying methods":active_record_querying.html inside the scope block. The following ones are discussed below:
-TIP: If you set the +:select+ option on a +belongs_to+ association, you should also set the +foreign_key+ option to guarantee the correct results.
+* +where+
+* +includes+
+* +readonly+
+* +select+
-h6(#belongs_to-touch). +:touch+
+h6(#belongs_to-where). +where+
-If you set the +:touch+ option to +:true+, then the +updated_at+ or +updated_on+ timestamp on the associated object will be set to the current time whenever this object is saved or destroyed:
+The +where+ method lets you specify the conditions that the associated object must meet.
<ruby>
class Order < ActiveRecord::Base
- belongs_to :customer, :touch => true
+ belongs_to :customer, -> { where :active => true }
+end
+</ruby>
+
+h6(#belongs_to-includes). +includes+
+
+You can use the +includes+ method let you specify second-order associations that should be eager-loaded when this association is used. For example, consider these models:
+
+<ruby>
+class LineItem < ActiveRecord::Base
+ belongs_to :order
+end
+
+class Order < ActiveRecord::Base
+ belongs_to :customer
+ has_many :line_items
end
class Customer < ActiveRecord::Base
@@ -817,17 +814,34 @@ class Customer < ActiveRecord::Base
end
</ruby>
-In this case, saving or destroying an order will update the timestamp on the associated customer. You can also specify a particular timestamp attribute to update:
+If you frequently retrieve customers directly from line items (+@line_item.order.customer+), then you can make your code somewhat more efficient by including customers in the association from line items to orders:
<ruby>
+class LineItem < ActiveRecord::Base
+ belongs_to :order, -> { includes :customer }
+end
+
class Order < ActiveRecord::Base
- belongs_to :customer, :touch => :orders_updated_at
+ belongs_to :customer
+ has_many :line_items
+end
+
+class Customer < ActiveRecord::Base
+ has_many :orders
end
</ruby>
-h6(#belongs_to-validate). +:validate+
+NOTE: There's no need to use +includes+ for immediate associations - that is, if you have +Order belongs_to :customer+, then the customer is eager-loaded automatically when it's needed.
-If you set the +:validate+ option to +true+, then associated objects will be validated whenever you save this object. By default, this is +false+: associated objects will not be validated when this object is saved.
+h6(#belongs_to-readonly). +readonly+
+
+If you use +readonly+, then the associated object will be read-only when retrieved via the association.
+
+h6(#belongs_to-select). +select+
+
+The +select+ method lets you override the SQL +SELECT+ clause that is used to retrieve data about the associated object. By default, Rails retrieves all columns.
+
+TIP: If you use the +select+ method on a +belongs_to+ association, you should also set the +:foreign_key+ option to guarantee the correct results.
h5(#belongs_to-do_any_associated_objects_exist). Do Any Associated Objects Exist?
@@ -924,15 +938,10 @@ The +has_one+ association supports these options:
* +:as+
* +:autosave+
* +:class_name+
-* +:conditions+
* +:dependent+
* +:foreign_key+
-* +:include+
* +:inverse_of+
-* +:order+
* +:primary_key+
-* +:readonly+
-* +:select+
* +:source+
* +:source_type+
* +:through+
@@ -956,16 +965,6 @@ class Supplier < ActiveRecord::Base
end
</ruby>
-h6(#has_one-conditions). +:conditions+
-
-The +:conditions+ option lets you specify the conditions that the associated object must meet (in the syntax used by an SQL +WHERE+ clause).
-
-<ruby>
-class Supplier < ActiveRecord::Base
- has_one :account, :conditions => "confirmed = 1"
-end
-</ruby>
-
h6(#has_one-dependent). +:dependent+
If you set the +:dependent+ option to +:destroy+, then deleting this object will call the +destroy+ method on the associated object to delete that object. If you set the +:dependent+ option to +:delete+, then deleting this object will delete the associated object _without_ calling its +destroy+ method. If you set the +:dependent+ option to +:nullify+, then deleting this object will set the foreign key in the association object to +NULL+.
@@ -985,30 +984,74 @@ end
TIP: In any case, Rails will not create foreign key columns for you. You need to explicitly define them as part of your migrations.
-h6(#has_one-include). +:include+
+h6(#has_one-inverse_of). +:inverse_of+
-You can use the +:include+ option to specify second-order associations that should be eager-loaded when this association is used. For example, consider these models:
+The +:inverse_of+ option specifies the name of the +belongs_to+ association that is the inverse of this association. Does not work in combination with the +:through+ or +:as+ options.
<ruby>
class Supplier < ActiveRecord::Base
- has_one :account
+ has_one :account, :inverse_of => :supplier
end
class Account < ActiveRecord::Base
- belongs_to :supplier
- belongs_to :representative
+ belongs_to :supplier, :inverse_of => :account
end
+</ruby>
-class Representative < ActiveRecord::Base
- has_many :accounts
+h6(#has_one-primary_key). +:primary_key+
+
+By convention, Rails assumes that the column used to hold the primary key of this model is +id+. You can override this and explicitly specify the primary key with the +:primary_key+ option.
+
+h6(#has_one-source). +:source+
+
+The +:source+ option specifies the source association name for a +has_one :through+ association.
+
+h6(#has_one-source_type). +:source_type+
+
+The +:source_type+ option specifies the source association type for a +has_one :through+ association that proceeds through a polymorphic association.
+
+h6(#has_one-through). +:through+
+
+The +:through+ option specifies a join model through which to perform the query. +has_one :through+ associations were discussed in detail <a href="#the-has_one-through-association">earlier in this guide</a>.
+
+h6(#has_one-validate). +:validate+
+
+If you set the +:validate+ option to +true+, then associated objects will be validated whenever you save this object. By default, this is +false+: associated objects will not be validated when this object is saved.
+
+h5(#belongs_to-scopes_for_has_one). Scopes for +has_one+
+
+There may be times when you wish to customize the query used by +has_one+. Such customizations can be achieved via a scope block. For example:
+
+<ruby>
+class Supplier < ActiveRecord::Base
+ has_one :account, -> { where :active => true }
end
</ruby>
-If you frequently retrieve representatives directly from suppliers (+@supplier.account.representative+), then you can make your code somewhat more efficient by including representatives in the association from suppliers to accounts:
+You can use any of the standard "querying methods":active_record_querying.html inside the scope block. The following ones are discussed below:
+
+* +where+
+* +includes+
+* +readonly+
+* +select+
+
+h6(#has_one-where). +where+
+
+The +where+ method lets you specify the conditions that the associated object must meet.
+
+<ruby>
+class Supplier < ActiveRecord::Base
+ has_one :account, -> { where "confirmed = 1" }
+end
+</ruby>
+
+h6(#has_one-includes). +includes+
+
+You can use the +includes+ method to specify second-order associations that should be eager-loaded when this association is used. For example, consider these models:
<ruby>
class Supplier < ActiveRecord::Base
- has_one :account, :include => :representative
+ has_one :account
end
class Account < ActiveRecord::Base
@@ -1021,51 +1064,30 @@ class Representative < ActiveRecord::Base
end
</ruby>
-h6(#has_one-inverse_of). +:inverse_of+
-
-The +:inverse_of+ option specifies the name of the +belongs_to+ association that is the inverse of this association. Does not work in combination with the +:through+ or +:as+ options.
+If you frequently retrieve representatives directly from suppliers (+@supplier.account.representative+), then you can make your code somewhat more efficient by including representatives in the association from suppliers to accounts:
<ruby>
class Supplier < ActiveRecord::Base
- has_one :account, :inverse_of => :supplier
+ has_one :account, -> { includes :representative }
end
class Account < ActiveRecord::Base
- belongs_to :supplier, :inverse_of => :account
+ belongs_to :supplier
+ belongs_to :representative
end
-</ruby>
-
-h6(#has_one-order). +:order+
-
-The +:order+ option dictates the order in which associated objects will be received (in the syntax used by an SQL +ORDER BY+ clause). Because a +has_one+ association will only retrieve a single associated object, this option should not be needed.
-
-h6(#has_one-primary_key). +:primary_key+
-
-By convention, Rails assumes that the column used to hold the primary key of this model is +id+. You can override this and explicitly specify the primary key with the +:primary_key+ option.
-
-h6(#has_one-readonly). +:readonly+
-
-If you set the +:readonly+ option to +true+, then the associated object will be read-only when retrieved via the association.
-
-h6(#has_one-select). +:select+
-
-The +:select+ option lets you override the SQL +SELECT+ clause that is used to retrieve data about the associated object. By default, Rails retrieves all columns.
-
-h6(#has_one-source). +:source+
-The +:source+ option specifies the source association name for a +has_one :through+ association.
-
-h6(#has_one-source_type). +:source_type+
-
-The +:source_type+ option specifies the source association type for a +has_one :through+ association that proceeds through a polymorphic association.
+class Representative < ActiveRecord::Base
+ has_many :accounts
+end
+</ruby>
-h6(#has_one-through). +:through+
+h6(#has_one-readonly). +readonly+
-The +:through+ option specifies a join model through which to perform the query. +has_one :through+ associations were discussed in detail <a href="#the-has_one-through-association">earlier in this guide</a>.
+If you use the +readonly+ method, then the associated object will be read-only when retrieved via the association.
-h6(#has_one-validate). +:validate+
+h6(#has_one-select). +select+
-If you set the +:validate+ option to +true+, then associated objects will be validated whenever you save this object. By default, this is +false+: associated objects will not be validated when this object is saved.
+The +select+ method lets you override the SQL +SELECT+ clause that is used to retrieve data about the associated object. By default, Rails retrieves all columns.
h5(#has_one-do_any_associated_objects_exist). Do Any Associated Objects Exist?
@@ -1256,23 +1278,13 @@ The +has_many+ association supports these options:
* +:as+
* +:autosave+
* +:class_name+
-* +:conditions+
* +:dependent+
-* +:extend+
* +:foreign_key+
-* +:group+
-* +:include+
* +:inverse_of+
-* +:limit+
-* +:offset+
-* +:order+
* +:primary_key+
-* +:readonly+
-* +:select+
* +:source+
* +:source_type+
* +:through+
-* +:uniq+
* +:validate+
h6(#has_many-as). +:as+
@@ -1293,75 +1305,124 @@ class Customer < ActiveRecord::Base
end
</ruby>
-h6(#has_many-conditions). +:conditions+
+h6(#has_many-dependent). +:dependent+
+
+If you set the +:dependent+ option to +:destroy+, then deleting this object will call the +destroy+ method on the associated objects to delete those objects. If you set the +:dependent+ option to +:delete_all+, then deleting this object will delete the associated objects _without_ calling their +destroy+ method. If you set the +:dependent+ option to +:nullify+, then deleting this object will set the foreign key in the associated objects to +NULL+.
+If you set the +:dependent+ option to +:restrict+, then the deletion of the object is restricted if a dependent associated object exist and a +DeleteRestrictionError+ exception is raised.
+
+NOTE: The default behavior for +:dependent => :restrict+ is to raise a +DeleteRestrictionError+ when associated objects exist. Since Rails 4.0 this behavior is being deprecated in favor of adding an error to the base model. To silence the warning in Rails 4.0, you should fix your code to not expect this Exception and add +config.active_record.dependent_restrict_raises = false+ to your application config.
+
+NOTE: This option is ignored when you use the +:through+ option on the association.
-The +:conditions+ option lets you specify the conditions that the associated object must meet (in the syntax used by an SQL +WHERE+ clause).
+h6(#has_many-foreign_key). +:foreign_key+
+
+By convention, Rails assumes that the column used to hold the foreign key on the other model is the name of this model with the suffix +_id+ added. The +:foreign_key+ option lets you set the name of the foreign key directly:
<ruby>
class Customer < ActiveRecord::Base
- has_many :confirmed_orders, :class_name => "Order",
- :conditions => "confirmed = 1"
+ has_many :orders, :foreign_key => "cust_id"
end
</ruby>
-You can also set conditions via a hash:
+TIP: In any case, Rails will not create foreign key columns for you. You need to explicitly define them as part of your migrations.
+
+h6(#has_many-inverse_of). +:inverse_of+
+
+The +:inverse_of+ option specifies the name of the +belongs_to+ association that is the inverse of this association. Does not work in combination with the +:through+ or +:as+ options.
<ruby>
class Customer < ActiveRecord::Base
- has_many :confirmed_orders, :class_name => "Order",
- :conditions => { :confirmed => true }
+ has_many :orders, :inverse_of => :customer
+end
+
+class Order < ActiveRecord::Base
+ belongs_to :customer, :inverse_of => :orders
end
</ruby>
-If you use a hash-style +:conditions+ option, then record creation via this association will be automatically scoped using the hash. In this case, using +@customer.confirmed_orders.create+ or +@customer.confirmed_orders.build+ will create orders where the confirmed column has the value +true+.
+h6(#has_many-primary_key). +:primary_key+
+
+By convention, Rails assumes that the column used to hold the primary key of the association is +id+. You can override this and explicitly specify the primary key with the +:primary_key+ option.
+
+h6(#has_many-source). +:source+
+
+The +:source+ option specifies the source association name for a +has_many :through+ association. You only need to use this option if the name of the source association cannot be automatically inferred from the association name.
+
+h6(#has_many-source_type). +:source_type+
+
+The +:source_type+ option specifies the source association type for a +has_many :through+ association that proceeds through a polymorphic association.
+
+h6(#has_many-through). +:through+
+
+The +:through+ option specifies a join model through which to perform the query. +has_many :through+ associations provide a way to implement many-to-many relationships, as discussed <a href="#the-has_many-through-association">earlier in this guide</a>.
+
+h6(#has_many-validate). +:validate+
+
+If you set the +:validate+ option to +false+, then associated objects will not be validated whenever you save this object. By default, this is +true+: associated objects will be validated when this object is saved.
-If you need to evaluate conditions dynamically at runtime, use a proc:
+h5(#has_many-scopes_for_has_many). Scopes for +has_many+
+
+There may be times when you wish to customize the query used by +has_many+. Such customizations can be achieved via a scope block. For example:
<ruby>
class Customer < ActiveRecord::Base
- has_many :latest_orders, :class_name => "Order",
- :conditions => proc { ["orders.created_at > ?", 10.hours.ago] }
+ has_many :orders, -> { where :processed => true }
end
</ruby>
-h6(#has_many-dependent). +:dependent+
-
-If you set the +:dependent+ option to +:destroy+, then deleting this object will call the +destroy+ method on the associated objects to delete those objects. If you set the +:dependent+ option to +:delete_all+, then deleting this object will delete the associated objects _without_ calling their +destroy+ method. If you set the +:dependent+ option to +:nullify+, then deleting this object will set the foreign key in the associated objects to +NULL+.
-If you set the +:dependent+ option to +:restrict+, then the deletion of the object is restricted if a dependent associated object exist and a +DeleteRestrictionError+ exception is raised.
-
-NOTE: The default behavior for +:dependent => :restrict+ is to raise a +DeleteRestrictionError+ when associated objects exist. Since Rails 4.0 this behavior is being deprecated in favor of adding an error to the base model. To silence the warning in Rails 4.0, you should fix your code to not expect this Exception and add +config.active_record.dependent_restrict_raises = false+ to your application config.
+You can use any of the standard "querying methods":active_record_querying.html inside the scope block. The following ones are discussed below:
-NOTE: This option is ignored when you use the +:through+ option on the association.
+* +where+
+* +extending+
+* +group+
+* +includes+
+* +limit+
+* +offset+
+* +order+
+* +readonly+
+* +select+
+* +uniq+
-h6(#has_many-extend). +:extend+
+h6(#has_many-where). +where+
-The +:extend+ option specifies a named module to extend the association proxy. Association extensions are discussed in detail <a href="#association-extensions">later in this guide</a>.
+The +where+ method lets you specify the conditions that the associated object must meet.
-h6(#has_many-foreign_key). +:foreign_key+
+<ruby>
+class Customer < ActiveRecord::Base
+ has_many :confirmed_orders, -> { where "confirmed = 1" },
+ :class_name => "Order"
+end
+</ruby>
-By convention, Rails assumes that the column used to hold the foreign key on the other model is the name of this model with the suffix +_id+ added. The +:foreign_key+ option lets you set the name of the foreign key directly:
+You can also set conditions via a hash:
<ruby>
class Customer < ActiveRecord::Base
- has_many :orders, :foreign_key => "cust_id"
+ has_many :confirmed_orders, -> { where :confirmed => true },
+ :class_name => "Order"
end
</ruby>
-TIP: In any case, Rails will not create foreign key columns for you. You need to explicitly define them as part of your migrations.
+If you use a hash-style +where+ option, then record creation via this association will be automatically scoped using the hash. In this case, using +@customer.confirmed_orders.create+ or +@customer.confirmed_orders.build+ will create orders where the confirmed column has the value +true+.
+
+h6(#has_many-extending). +extending+
-h6(#has_many-group). +:group+
+The +extending+ method specifies a named module to extend the association proxy. Association extensions are discussed in detail <a href="#association-extensions">later in this guide</a>.
-The +:group+ option supplies an attribute name to group the result set by, using a +GROUP BY+ clause in the finder SQL.
+h6(#has_many-group). +group+
+
+The +group+ method supplies an attribute name to group the result set by, using a +GROUP BY+ clause in the finder SQL.
<ruby>
class Customer < ActiveRecord::Base
- has_many :line_items, :through => :orders, :group => "orders.id"
+ has_many :line_items, -> { group 'orders.id' },
+ :through => :orders
end
</ruby>
-h6(#has_many-include). +:include+
+h6(#has_many-includes). +includes+
-You can use the +:include+ option to specify second-order associations that should be eager-loaded when this association is used. For example, consider these models:
+You can use the +includes+ method to specify second-order associations that should be eager-loaded when this association is used. For example, consider these models:
<ruby>
class Customer < ActiveRecord::Base
@@ -1382,7 +1443,7 @@ If you frequently retrieve line items directly from customers (+@customer.orders
<ruby>
class Customer < ActiveRecord::Base
- has_many :orders, :include => :line_items
+ has_many :orders, -> { includes :line_items }
end
class Order < ActiveRecord::Base
@@ -1395,74 +1456,45 @@ class LineItem < ActiveRecord::Base
end
</ruby>
-h6(#has_many-inverse_of). +:inverse_of+
-
-The +:inverse_of+ option specifies the name of the +belongs_to+ association that is the inverse of this association. Does not work in combination with the +:through+ or +:as+ options.
-
-<ruby>
-class Customer < ActiveRecord::Base
- has_many :orders, :inverse_of => :customer
-end
-
-class Order < ActiveRecord::Base
- belongs_to :customer, :inverse_of => :orders
-end
-</ruby>
-
-h6(#has_many-limit). +:limit+
+h6(#has_many-limit). +limit+
-The +:limit+ option lets you restrict the total number of objects that will be fetched through an association.
+The +limit+ method lets you restrict the total number of objects that will be fetched through an association.
<ruby>
class Customer < ActiveRecord::Base
- has_many :recent_orders, :class_name => "Order",
- :order => "order_date DESC", :limit => 100
+ has_many :recent_orders,
+ -> { order('order_date desc').limit(100) },
+ :class_name => "Order",
end
</ruby>
-h6(#has_many-offset). +:offset+
+h6(#has_many-offset). +offset+
-The +:offset+ option lets you specify the starting offset for fetching objects via an association. For example, if you set +:offset => 11+, it will skip the first 11 records.
+The +offset+ method lets you specify the starting offset for fetching objects via an association. For example, +-> { offset(11) }+ will skip the first 11 records.
-h6(#has_many-order). +:order+
+h6(#has_many-order). +order+
-The +:order+ option dictates the order in which associated objects will be received (in the syntax used by an SQL +ORDER BY+ clause).
+The +order+ method dictates the order in which associated objects will be received (in the syntax used by an SQL +ORDER BY+ clause).
<ruby>
class Customer < ActiveRecord::Base
- has_many :orders, :order => "date_confirmed DESC"
+ has_many :orders, -> { order "date_confirmed DESC" }
end
</ruby>
-h6(#has_many-primary_key). +:primary_key+
-
-By convention, Rails assumes that the column used to hold the primary key of the association is +id+. You can override this and explicitly specify the primary key with the +:primary_key+ option.
-
-h6(#has_many-readonly). +:readonly+
-
-If you set the +:readonly+ option to +true+, then the associated objects will be read-only when retrieved via the association.
-
-h6(#has_many-select). +:select+
-
-The +:select+ option lets you override the SQL +SELECT+ clause that is used to retrieve data about the associated objects. By default, Rails retrieves all columns.
-
-WARNING: If you specify your own +:select+, be sure to include the primary key and foreign key columns of the associated model. If you do not, Rails will throw an error.
-
-h6(#has_many-source). +:source+
-
-The +:source+ option specifies the source association name for a +has_many :through+ association. You only need to use this option if the name of the source association cannot be automatically inferred from the association name.
+h6(#has_many-readonly). +readonly+
-h6(#has_many-source_type). +:source_type+
+If you use the +readonly+ method, then the associated objects will be read-only when retrieved via the association.
-The +:source_type+ option specifies the source association type for a +has_many :through+ association that proceeds through a polymorphic association.
+h6(#has_many-select). +select+
-h6(#has_many-through). +:through+
+The +select+ method lets you override the SQL +SELECT+ clause that is used to retrieve data about the associated objects. By default, Rails retrieves all columns.
-The +:through+ option specifies a join model through which to perform the query. +has_many :through+ associations provide a way to implement many-to-many relationships, as discussed <a href="#the-has_many-through-association">earlier in this guide</a>.
+WARNING: If you specify your own +select+, be sure to include the primary key and foreign key columns of the associated model. If you do not, Rails will throw an error.
-h6(#has_many-uniq). +:uniq+
+h6(#has_many-uniq). +uniq+
-Set the +:uniq+ option to true to keep the collection free of duplicates. This is mostly useful together with the +:through+ option.
+Use the +uniq+ method to keep the collection free of duplicates. This is mostly useful together with the +:through+ option.
<ruby>
class Person < ActiveRecord::Base
@@ -1480,12 +1512,12 @@ Reading.all.inspect # => [#<Reading id: 12, person_id: 5, post_id: 5>, #<Readin
In the above case there are two readings and +person.posts+ brings out both of them even though these records are pointing to the same post.
-Now let's set +:uniq+ to true:
+Now let's set +uniq+:
<ruby>
class Person
has_many :readings
- has_many :posts, :through => :readings, :uniq => true
+ has_many :posts, -> { uniq }, :through => :readings
end
person = Person.create(:name => 'honda')
@@ -1498,10 +1530,6 @@ Reading.all.inspect # => [#<Reading id: 16, person_id: 7, post_id: 7>, #<Readin
In the above case there are still two readings. However +person.posts+ shows only one post because the collection loads only unique records.
-h6(#has_many-validate). +:validate+
-
-If you set the +:validate+ option to +false+, then associated objects will not be validated whenever you save this object. By default, this is +true+: associated objects will be validated when this object is saved.
-
h5(#has_many-when_are_objects_saved). When are Objects Saved?
When you assign an object to a +has_many+ association, that object is automatically saved (in order to update its foreign key). If you assign multiple objects in one statement, then they are all saved.
@@ -1687,18 +1715,8 @@ The +has_and_belongs_to_many+ association supports these options:
* +:association_foreign_key+
* +:autosave+
* +:class_name+
-* +:conditions+
-* +:extend+
* +:foreign_key+
-* +:group+
-* +:include+
* +:join_table+
-* +:limit+
-* +:offset+
-* +:order+
-* +:readonly+
-* +:select+
-* +:uniq+
* +:validate+
h6(#has_and_belongs_to_many-association_foreign_key). +:association_foreign_key+
@@ -1729,102 +1747,126 @@ class Parts < ActiveRecord::Base
end
</ruby>
-h6(#has_and_belongs_to_many-conditions). +:conditions+
+h6(#has_and_belongs_to_many-foreign_key). +:foreign_key+
-The +:conditions+ option lets you specify the conditions that the associated object must meet (in the syntax used by an SQL +WHERE+ clause).
+By convention, Rails assumes that the column in the join table used to hold the foreign key pointing to this model is the name of this model with the suffix +_id+ added. The +:foreign_key+ option lets you set the name of the foreign key directly:
<ruby>
-class Parts < ActiveRecord::Base
- has_and_belongs_to_many :assemblies,
- :conditions => "factory = 'Seattle'"
+class User < ActiveRecord::Base
+ has_and_belongs_to_many :friends, :class_name => "User",
+ :foreign_key => "this_user_id",
+ :association_foreign_key => "other_user_id"
end
</ruby>
-You can also set conditions via a hash:
+h6(#has_and_belongs_to_many-join_table). +:join_table+
+
+If the default name of the join table, based on lexical ordering, is not what you want, you can use the +:join_table+ option to override the default.
+
+h6(#has_and_belongs_to_many-validate). +:validate+
+
+If you set the +:validate+ option to +false+, then associated objects will not be validated whenever you save this object. By default, this is +true+: associated objects will be validated when this object is saved.
+
+h5(#has_and_belongs_to_many-scopes_for_has_and_belongs_to_many). Scopes for +has_and_belongs_to_many+
+
+There may be times when you wish to customize the query used by +has_and_belongs_to_many+. Such customizations can be achieved via a scope block. For example:
<ruby>
class Parts < ActiveRecord::Base
- has_and_belongs_to_many :assemblies,
- :conditions => { :factory => 'Seattle' }
+ has_and_belongs_to_many :assemblies, -> { where :active => true }
end
</ruby>
-If you use a hash-style +:conditions+ option, then record creation via this association will be automatically scoped using the hash. In this case, using +@parts.assemblies.create+ or +@parts.assemblies.build+ will create orders where the +factory+ column has the value "Seattle".
+You can use any of the standard "querying methods":active_record_querying.html inside the scope block. The following ones are discussed below:
-h6(#has_and_belongs_to_many-extend). +:extend+
+* +where+
+* +extending+
+* +group+
+* +includes+
+* +limit+
+* +offset+
+* +order+
+* +readonly+
+* +select+
+* +uniq+
-The +:extend+ option specifies a named module to extend the association proxy. Association extensions are discussed in detail <a href="#association-extensions">later in this guide</a>.
+h6(#has_and_belongs_to_many-where). +where+
-h6(#has_and_belongs_to_many-foreign_key). +:foreign_key+
-
-By convention, Rails assumes that the column in the join table used to hold the foreign key pointing to this model is the name of this model with the suffix +_id+ added. The +:foreign_key+ option lets you set the name of the foreign key directly:
+The +where+ method lets you specify the conditions that the associated object must meet.
<ruby>
-class User < ActiveRecord::Base
- has_and_belongs_to_many :friends, :class_name => "User",
- :foreign_key => "this_user_id",
- :association_foreign_key => "other_user_id"
+class Parts < ActiveRecord::Base
+ has_and_belongs_to_many :assemblies,
+ -> { where "factory = 'Seattle'" }
end
</ruby>
-h6(#has_and_belongs_to_many-group). +:group+
-
-The +:group+ option supplies an attribute name to group the result set by, using a +GROUP BY+ clause in the finder SQL.
+You can also set conditions via a hash:
<ruby>
class Parts < ActiveRecord::Base
- has_and_belongs_to_many :assemblies, :group => "factory"
+ has_and_belongs_to_many :assemblies,
+ -> { where :factory => 'Seattle' }
end
</ruby>
-h6(#has_and_belongs_to_many-include). +:include+
-
-You can use the +:include+ option to specify second-order associations that should be eager-loaded when this association is used.
+If you use a hash-style +where+, then record creation via this association will be automatically scoped using the hash. In this case, using +@parts.assemblies.create+ or +@parts.assemblies.build+ will create orders where the +factory+ column has the value "Seattle".
-h6(#has_and_belongs_to_many-join_table). +:join_table+
+h6(#has_and_belongs_to_many-extending). +extending+
-If the default name of the join table, based on lexical ordering, is not what you want, you can use the +:join_table+ option to override the default.
+The +extending+ method specifies a named module to extend the association proxy. Association extensions are discussed in detail <a href="#association-extensions">later in this guide</a>.
-h6(#has_and_belongs_to_many-limit). +:limit+
+h6(#has_and_belongs_to_many-group). +group+
-The +:limit+ option lets you restrict the total number of objects that will be fetched through an association.
+The +group+ method supplies an attribute name to group the result set by, using a +GROUP BY+ clause in the finder SQL.
<ruby>
class Parts < ActiveRecord::Base
- has_and_belongs_to_many :assemblies, :order => "created_at DESC",
- :limit => 50
+ has_and_belongs_to_many :assemblies, -> { group "factory" }
end
</ruby>
-h6(#has_and_belongs_to_many-offset). +:offset+
+h6(#has_and_belongs_to_many-includes). +includes+
-The +:offset+ option lets you specify the starting offset for fetching objects via an association. For example, if you set +:offset => 11+, it will skip the first 11 records.
+You can use the +includes+ method to specify second-order associations that should be eager-loaded when this association is used.
-h6(#has_and_belongs_to_many-order). +:order+
+h6(#has_and_belongs_to_many-limit). +limit+
-The +:order+ option dictates the order in which associated objects will be received (in the syntax used by an SQL +ORDER BY+ clause).
+The +limit+ method lets you restrict the total number of objects that will be fetched through an association.
<ruby>
class Parts < ActiveRecord::Base
- has_and_belongs_to_many :assemblies, :order => "assembly_name ASC"
+ has_and_belongs_to_many :assemblies,
+ -> { order("created_at DESC").limit(50) }
end
</ruby>
-h6(#has_and_belongs_to_many-readonly). +:readonly+
+h6(#has_and_belongs_to_many-offset). +offset+
-If you set the +:readonly+ option to +true+, then the associated objects will be read-only when retrieved via the association.
+The +offset+ method lets you specify the starting offset for fetching objects via an association. For example, if you set +offset(11)+, it will skip the first 11 records.
-h6(#has_and_belongs_to_many-select). +:select+
+h6(#has_and_belongs_to_many-order). +order+
-The +:select+ option lets you override the SQL +SELECT+ clause that is used to retrieve data about the associated objects. By default, Rails retrieves all columns.
+The +order+ method dictates the order in which associated objects will be received (in the syntax used by an SQL +ORDER BY+ clause).
-h6(#has_and_belongs_to_many-uniq). +:uniq+
+<ruby>
+class Parts < ActiveRecord::Base
+ has_and_belongs_to_many :assemblies,
+ -> { order "assembly_name ASC" }
+end
+</ruby>
-Specify the +:uniq => true+ option to remove duplicates from the collection.
+h6(#has_and_belongs_to_many-readonly). +readonly+
-h6(#has_and_belongs_to_many-validate). +:validate+
+If you use the +readonly+ method, then the associated objects will be read-only when retrieved via the association.
-If you set the +:validate+ option to +false+, then associated objects will not be validated whenever you save this object. By default, this is +true+: associated objects will be validated when this object is saved.
+h6(#has_and_belongs_to_many-select). +select+
+
+The +select+ method lets you override the SQL +SELECT+ clause that is used to retrieve data about the associated objects. By default, Rails retrieves all columns.
+
+h6(#has_and_belongs_to_many-uniq). +uniq+
+
+Use the +uniq+ method to remove duplicates from the collection.
h5(#has_and_belongs_to_many-when_are_objects_saved). When are Objects Saved?
@@ -1904,20 +1946,11 @@ module FindRecentExtension
end
class Customer < ActiveRecord::Base
- has_many :orders, :extend => FindRecentExtension
+ has_many :orders, -> { extending FindRecentExtension }
end
class Supplier < ActiveRecord::Base
- has_many :deliveries, :extend => FindRecentExtension
-end
-</ruby>
-
-To include more than one extension module in a single association, specify an array of modules:
-
-<ruby>
-class Customer < ActiveRecord::Base
- has_many :orders,
- :extend => [FindRecentExtension, FindActiveExtension]
+ has_many :deliveries, -> { extending FindRecentExtension }
end
</ruby>