Very Important in has_and-belongs_to_many
4.4 has_and_belongs_to_many Association Reference
The has_and_belongs_to_many association creates a many-to-many relationship with another model. In database terms, this associates two classes via an intermediate join table that includes foreign keys referring to each of the classes.
4.4.1 Methods Added by has_and_belongs_to_many
When you declare a has_and_belongs_to_many association, the declaring class automatically gains 17 methods related to the association:
collectioncollection<<(object, ...)collection.delete(object, ...)collection.destroy(object, ...)collection=(objects)collection_singular_idscollection_singular_ids=(ids)collection.clearcollection.empty?collection.sizecollection.find(...)collection.where(...)collection.exists?(...)collection.build(attributes = {})collection.create(attributes = {})collection.create!(attributes = {})collection.reload
In all of these methods, collection is replaced with the symbol passed as the first argument to has_and_belongs_to_many, and collection_singular is replaced with the singularized version of that symbol. For example, given the declaration:
Each instance of the Part model will have these methods:
4.4.1.1 Additional Column Methods
If the join table for a has_and_belongs_to_many association has additional columns beyond the two foreign keys, these columns will be added as attributes to records retrieved via that association. Records returned with additional attributes will always be read-only, because Rails cannot save changes to those attributes.
The use of extra attributes on the join table in a has_and_belongs_to_many association is deprecated. If you require this sort of complex behavior on the table that joins two models in a many-to-many relationship, you should use a has_many :through association instead of has_and_belongs_to_many.
4.4.1.2 collection
The collection method returns a Relation of all of the associated objects. If there are no associated objects, it returns an empty Relation.
4.4.1.3 collection<<(object, ...)
The collection<< method adds one or more objects to the collection by creating records in the join table.
This method is aliased as collection.concat and collection.push.
4.4.1.4 collection.delete(object, ...)
The collection.delete method removes one or more objects from the collection by deleting records in the join table. This does not destroy the objects.
4.4.1.5 collection.destroy(object, ...)
The collection.destroy method removes one or more objects from the collection by deleting records in the join table. This does not destroy the objects.
4.4.1.6 collection=(objects)
The collection= method makes the collection contain only the supplied objects, by adding and deleting as appropriate. The changes are persisted to the database.
4.4.1.7 collection_singular_ids
The collection_singular_ids method returns an array of the ids of the objects in the collection.
4.4.1.8 collection_singular_ids=(ids)
The collection_singular_ids= method makes the collection contain only the objects identified by the supplied primary key values, by adding and deleting as appropriate. The changes are persisted to the database.
4.4.1.9 collection.clear
The collection.clear method removes every object from the collection by deleting the rows from the joining table. This does not destroy the associated objects.
4.4.1.10 collection.empty?
The collection.empty? method returns true if the collection does not contain any associated objects.
4.4.1.11 collection.size
The collection.size method returns the number of objects in the collection.
4.4.1.12 collection.find(...)
The collection.find method finds objects within the collection. It uses the same syntax and options as ActiveRecord::Base.find.
4.4.1.13 collection.where(...)
The collection.where method finds objects within the collection based on the conditions supplied but the objects are loaded lazily meaning that the database is queried only when the object(s) are accessed.
4.4.1.14 collection.exists?(...)
The collection.exists? method checks whether an object meeting the supplied conditions exists in the collection. It uses the same syntax and options as ActiveRecord::Base.exists?.
4.4.1.15 collection.build(attributes = {})
The collection.build method returns a new object of the associated type. This object will be instantiated from the passed attributes, and the link through the join table will be created, but the associated object will not yet be saved.
4.4.1.16 collection.create(attributes = {})
The collection.create method returns a new object of the associated type. This object will be instantiated from the passed attributes, the link through the join table will be created, and, once it passes all of the validations specified on the associated model, the associated object will be saved.
4.4.1.17 collection.create!(attributes = {})
Does the same as collection.create, but raises ActiveRecord::RecordInvalid if the record is invalid.
4.4.1.18 collection.reload
The collection.reload method returns a Relation of all of the associated objects, forcing a database read. If there are no associated objects, it returns an empty Relation.
4.4.2 Options for has_and_belongs_to_many
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 has_and_belongs_to_many association reference. Such customizations can easily be accomplished by passing options when you create the association. For example, this association uses two such options:
The has_and_belongs_to_many association supports these options:
:association_foreign_key:autosave:class_name:foreign_key:join_table:validate
4.4.2.1 :association_foreign_key
By convention, Rails assumes that the column in the join table used to hold the foreign key pointing to the other model is the name of that model with the suffix _id added. The :association_foreign_key option lets you set the name of the foreign key directly:
The :foreign_key and :association_foreign_key options are useful when setting up a many-to-many self-join. For example:
4.4.2.2 :autosave
If you set the :autosave option to true, Rails will save any loaded association members and destroy members that are marked for destruction whenever you save the parent object. Setting :autosave to false is not the same as not setting the :autosave option. If the :autosave option is not present, then new associated objects will be saved, but updated associated objects will not be saved.
4.4.2.3 :class_name
If the name of the other model cannot be derived from the association name, you can use the :class_name option to supply the model name. For example, if a part has many assemblies, but the actual name of the model containing assemblies is Gadget, you'd set things up this way:
4.4.2.4 :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:
4.4.2.5 :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.
4.4.2.6 :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.
4.4.3 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:
You can use any of the standard querying methods inside the scope block. The following ones are discussed below:
whereextendinggroupincludeslimitoffsetorderreadonlyselectdistinct
4.4.3.1 where
The where method lets you specify the conditions that the associated object must meet.
You can also set conditions via a hash:
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".
4.4.3.2 extending
The extending method specifies a named module to extend the association proxy. Association extensions are discussed in detail later in this guide.
4.4.3.3 group
The group method supplies an attribute name to group the result set by, using a GROUP BY clause in the finder SQL.
4.4.3.4 includes
You can use the includes method to specify second-order associations that should be eager-loaded when this association is used.
4.4.3.5 limit
The limit method lets you restrict the total number of objects that will be fetched through an association.
4.4.3.6 offset
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.
4.4.3.7 order
The order method dictates the order in which associated objects will be received (in the syntax used by an SQL ORDER BY clause).
4.4.3.8 readonly
If you use the readonly method, then the associated objects will be read-only when retrieved via the association.
4.4.3.9 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.
4.4.3.10 distinct
Use the distinct method to remove duplicates from the collection.
4.4.4 When are Objects Saved?
When you assign an object to a has_and_belongs_to_many association, that object is automatically saved (in order to update the join table). If you assign multiple objects in one statement, then they are all saved.
If any of these saves fails due to validation errors, then the assignment statement returns false and the assignment itself is cancelled.
If the parent object (the one declaring the has_and_belongs_to_many association) is unsaved (that is, new_record? returns true) then the child objects are not saved when they are added. All unsaved members of the association will automatically be saved when the parent is saved.
If you want to assign an object to a has_and_belongs_to_many association without saving the object, use the collection.build method.
Comments
Post a Comment