aboutsummaryrefslogtreecommitdiffstats
path: root/guides/source/association_basics.md
diff options
context:
space:
mode:
Diffstat (limited to 'guides/source/association_basics.md')
-rw-r--r--guides/source/association_basics.md459
1 files changed, 337 insertions, 122 deletions
diff --git a/guides/source/association_basics.md b/guides/source/association_basics.md
index 42c7c07745..c0482f6106 100644
--- a/guides/source/association_basics.md
+++ b/guides/source/association_basics.md
@@ -1,11 +1,13 @@
-A Guide to Active Record Associations
-=====================================
+Active Record Associations
+==========================
-This guide covers the association features of Active Record. By referring to this guide, you will be able to:
+This guide covers the association features of Active Record.
-* Declare associations between Active Record models
-* Understand the various types of Active Record associations
-* Use the methods added to your models by creating associations
+After reading this guide, you will know:
+
+* How to declare associations between Active Record models.
+* How to understand the various types of Active Record associations.
+* How to use the methods added to your models by creating associations.
--------------------------------------------------------------------------------
@@ -25,25 +27,24 @@ end
Now, suppose we wanted to add a new order for an existing customer. We'd need to do something like this:
```ruby
-@order = Order.create(:order_date => Time.now,
- :customer_id => @customer.id)
+@order = Order.create(order_date: Time.now, customer_id: @customer.id)
```
Or consider deleting a customer, and ensuring that all of its orders get deleted as well:
```ruby
-@orders = Order.where(:customer_id => @customer.id)
+@orders = Order.where(customer_id: @customer.id)
@orders.each do |order|
order.destroy
end
@customer.destroy
```
-With Active Record associations, we can streamline these -- and other -- operations by declaratively telling Rails that there is a connection between the two models. Here's the revised code for setting up customers and orders:
+With Active Record associations, we can streamline these - and other - operations by declaratively telling Rails that there is a connection between the two models. Here's the revised code for setting up customers and orders:
```ruby
class Customer < ActiveRecord::Base
- has_many :orders, :dependent => :destroy
+ has_many :orders, dependent: :destroy
end
class Order < ActiveRecord::Base
@@ -54,10 +55,10 @@ end
With this change, creating a new order for a particular customer is easier:
```ruby
-@order = @customer.orders.create(:order_date => Time.now)
+@order = @customer.orders.create(order_date: Time.now)
```
-Deleting a customer and all of its orders is _much_ easier:
+Deleting a customer and all of its orders is *much* easier:
```ruby
@customer.destroy
@@ -68,7 +69,7 @@ To learn more about the different types of associations, read the next section o
The Types of Associations
-------------------------
-In Rails, an _association_ is a connection between two Active Record models. Associations are implemented using macro-style calls, so that you can declaratively add features to your models. For example, by declaring that one model `belongs_to` another, you instruct Rails to maintain Primary Key–Foreign Key information between instances of the two models, and you also get a number of utility methods added to your model. Rails supports six types of associations:
+In Rails, an _association_ is a connection between two Active Record models. Associations are implemented using macro-style calls, so that you can declaratively add features to your models. For example, by declaring that one model `belongs_to` another, you instruct Rails to maintain Primary Key-Foreign Key information between instances of the two models, and you also get a number of utility methods added to your model. Rails supports six types of associations:
* `belongs_to`
* `has_one`
@@ -93,6 +94,25 @@ end
NOTE: `belongs_to` associations _must_ use the singular term. If you used the pluralized form in the above example for the `customer` association in the `Order` model, you would be told that there was an "uninitialized constant Order::Customers". This is because Rails automatically infers the class name from the association name. If the association name is wrongly pluralized, then the inferred class will be wrongly pluralized too.
+The corresponding migration might look like this:
+
+```ruby
+class CreateOrders < ActiveRecord::Migration
+ def change
+ create_table :customers do |t|
+ t.string :name
+ t.timestamps
+ end
+
+ create_table :orders do |t|
+ t.belongs_to :customer
+ t.datetime :order_date
+ t.timestamps
+ end
+ end
+end
+```
+
### The `has_one` Association
A `has_one` association also sets up a one-to-one connection with another model, but with somewhat different semantics (and consequences). This association indicates that each instance of a model contains or possesses one instance of another model. For example, if each supplier in your application has only one account, you'd declare the supplier model like this:
@@ -105,6 +125,25 @@ end
![has_one Association Diagram](images/has_one.png)
+The corresponding migration might look like this:
+
+```ruby
+class CreateSuppliers < ActiveRecord::Migration
+ def change
+ create_table :suppliers do |t|
+ t.string :name
+ t.timestamps
+ end
+
+ create_table :accounts do |t|
+ t.belongs_to :supplier
+ t.string :account_number
+ t.timestamps
+ end
+ end
+end
+```
+
### The `has_many` Association
A `has_many` association indicates a one-to-many connection with another model. You'll often find this association on the "other side" of a `belongs_to` association. This association indicates that each instance of the model has zero or more instances of another model. For example, in an application containing customers and orders, the customer model could be declared like this:
@@ -119,6 +158,25 @@ NOTE: The name of the other model is pluralized when declaring a `has_many` asso
![has_many Association Diagram](images/has_many.png)
+The corresponding migration might look like this:
+
+```ruby
+class CreateCustomers < ActiveRecord::Migration
+ def change
+ create_table :customers do |t|
+ t.string :name
+ t.timestamps
+ end
+
+ create_table :orders do |t|
+ t.belongs_to :customer
+ t.datetime :order_date
+ t.timestamps
+ end
+ end
+end
+```
+
### The `has_many :through` Association
A `has_many :through` association is often used to set up a many-to-many connection with another model. This association indicates that the declaring model can be matched with zero or more instances of another model by proceeding _through_ a third model. For example, consider a medical practice where patients make appointments to see physicians. The relevant association declarations could look like this:
@@ -126,7 +184,7 @@ A `has_many :through` association is often used to set up a many-to-many connect
```ruby
class Physician < ActiveRecord::Base
has_many :appointments
- has_many :patients, :through => :appointments
+ has_many :patients, through: :appointments
end
class Appointment < ActiveRecord::Base
@@ -136,12 +194,37 @@ end
class Patient < ActiveRecord::Base
has_many :appointments
- has_many :physicians, :through => :appointments
+ has_many :physicians, through: :appointments
end
```
![has_many :through Association Diagram](images/has_many_through.png)
+The corresponding migration might look like this:
+
+```ruby
+class CreateAppointments < ActiveRecord::Migration
+ def change
+ create_table :physicians do |t|
+ t.string :name
+ t.timestamps
+ end
+
+ create_table :patients do |t|
+ t.string :name
+ t.timestamps
+ end
+
+ create_table :appointments do |t|
+ t.belongs_to :physician
+ t.belongs_to :patient
+ t.datetime :appointment_date
+ t.timestamps
+ end
+ end
+end
+```
+
The collection of join models can be managed via the API. For example, if you assign
```ruby
@@ -157,7 +240,7 @@ The `has_many :through` association is also useful for setting up "shortcuts" th
```ruby
class Document < ActiveRecord::Base
has_many :sections
- has_many :paragraphs, :through => :sections
+ has_many :paragraphs, through: :sections
end
class Section < ActiveRecord::Base
@@ -170,7 +253,7 @@ class Paragraph < ActiveRecord::Base
end
```
-With `:through => :sections` specified, Rails will now understand:
+With `through: :sections` specified, Rails will now understand:
```ruby
@document.paragraphs
@@ -178,12 +261,15 @@ With `:through => :sections` specified, Rails will now understand:
### The `has_one :through` Association
-A `has_one :through` association sets up a one-to-one connection with another model. This association indicates that the declaring model can be matched with one instance of another model by proceeding _through_ a third model. For example, if each supplier has one account, and each account is associated with one account history, then the customer model could look like this:
+A `has_one :through` association sets up a one-to-one connection with another model. This association indicates
+that the declaring model can be matched with one instance of another model by proceeding _through_ a third model.
+For example, if each supplier has one account, and each account is associated with one account history, then the
+supplier model could look like this:
```ruby
class Supplier < ActiveRecord::Base
has_one :account
- has_one :account_history, :through => :account
+ has_one :account_history, through: :account
end
class Account < ActiveRecord::Base
@@ -198,6 +284,31 @@ end
![has_one :through Association Diagram](images/has_one_through.png)
+The corresponding migration might look like this:
+
+```ruby
+class CreateAccountHistories < ActiveRecord::Migration
+ def change
+ create_table :suppliers do |t|
+ t.string :name
+ t.timestamps
+ end
+
+ create_table :accounts do |t|
+ t.belongs_to :supplier
+ t.string :account_number
+ t.timestamps
+ end
+
+ create_table :account_histories do |t|
+ t.belongs_to :account
+ t.integer :credit_rating
+ t.timestamps
+ end
+ end
+end
+```
+
### The `has_and_belongs_to_many` Association
A `has_and_belongs_to_many` association creates a direct many-to-many connection with another model, with no intervening model. For example, if your application includes assemblies and parts, with each assembly having many parts and each part appearing in many assemblies, you could declare the models this way:
@@ -214,6 +325,29 @@ end
![has_and_belongs_to_many Association Diagram](images/habtm.png)
+The corresponding migration might look like this:
+
+```ruby
+class CreateAssembliesAndParts < ActiveRecord::Migration
+ def change
+ create_table :assemblies do |t|
+ t.string :name
+ t.timestamps
+ end
+
+ create_table :parts do |t|
+ t.string :part_number
+ t.timestamps
+ end
+
+ create_table :assemblies_parts, id: false do |t|
+ t.belongs_to :assembly
+ t.belongs_to :part
+ end
+ end
+end
+```
+
### Choosing Between `belongs_to` and `has_one`
If you want to set up a one-to-one relationship between two models, you'll need to add `belongs_to` to one, and `has_one` to the other. How do you know which is which?
@@ -270,7 +404,7 @@ The second way to declare a many-to-many relationship is to use `has_many :throu
```ruby
class Assembly < ActiveRecord::Base
has_many :manifests
- has_many :parts, :through => :manifests
+ has_many :parts, through: :manifests
end
class Manifest < ActiveRecord::Base
@@ -280,7 +414,7 @@ end
class Part < ActiveRecord::Base
has_many :manifests
- has_many :assemblies, :through => :manifests
+ has_many :assemblies, through: :manifests
end
```
@@ -294,15 +428,15 @@ A slightly more advanced twist on associations is the _polymorphic association_.
```ruby
class Picture < ActiveRecord::Base
- belongs_to :imageable, :polymorphic => true
+ belongs_to :imageable, polymorphic: true
end
class Employee < ActiveRecord::Base
- has_many :pictures, :as => :imageable
+ has_many :pictures, as: :imageable
end
class Product < ActiveRecord::Base
- has_many :pictures, :as => :imageable
+ has_many :pictures, as: :imageable
end
```
@@ -332,7 +466,7 @@ class CreatePictures < ActiveRecord::Migration
def change
create_table :pictures do |t|
t.string :name
- t.references :imageable, :polymorphic => true
+ t.references :imageable, polymorphic: true
t.timestamps
end
end
@@ -347,9 +481,10 @@ In designing a data model, you will sometimes find a model that should have a re
```ruby
class Employee < ActiveRecord::Base
- has_many :subordinates, :class_name => "Employee",
- :foreign_key => "manager_id"
- belongs_to :manager, :class_name => "Employee"
+ has_many :subordinates, class_name: "Employee",
+ foreign_key: "manager_id"
+
+ belongs_to :manager, class_name: "Employee"
end
```
@@ -440,9 +575,9 @@ end
These need to be backed up by a migration to create the `assemblies_parts` table. This table should be created without a primary key:
```ruby
-class CreateAssemblyPartJoinTable < ActiveRecord::Migration
+class CreateAssembliesPartsJoinTable < ActiveRecord::Migration
def change
- create_table :assemblies_parts, :id => false do |t|
+ create_table :assemblies_parts, id: false do |t|
t.integer :assembly_id
t.integer :part_id
end
@@ -450,7 +585,7 @@ class CreateAssemblyPartJoinTable < ActiveRecord::Migration
end
```
-We pass `:id => false` to `create_table` because that table does not represent a model. That's required for the association to work properly. If you observe any strange behavior in a `has_and_belongs_to_many` association like mangled models IDs, or exceptions about conflicting IDs chances are you forgot that bit.
+We pass `id: false` to `create_table` because that table does not represent a model. That's required for the association to work properly. If you observe any strange behavior in a `has_and_belongs_to_many` association like mangled models IDs, or exceptions about conflicting IDs, chances are you forgot that bit.
### Controlling Association Scope
@@ -495,14 +630,14 @@ module MyApplication
module Business
class Supplier < ActiveRecord::Base
has_one :account,
- :class_name => "MyApplication::Billing::Account"
+ class_name: "MyApplication::Billing::Account"
end
end
module Billing
class Account < ActiveRecord::Base
belongs_to :supplier,
- :class_name => "MyApplication::Business::Supplier"
+ class_name: "MyApplication::Business::Supplier"
end
end
end
@@ -536,11 +671,11 @@ This happens because c and o.customer are two different in-memory representation
```ruby
class Customer < ActiveRecord::Base
- has_many :orders, :inverse_of => :customer
+ has_many :orders, inverse_of: :customer
end
class Order < ActiveRecord::Base
- belongs_to :customer, :inverse_of => :orders
+ belongs_to :customer, inverse_of: :orders
end
```
@@ -561,6 +696,17 @@ There are a few limitations to `inverse_of` support:
* They do not work with `:as` associations.
* For `belongs_to` associations, `has_many` inverse associations are ignored.
+Every association will attempt to automatically find the inverse association
+and set the `:inverse_of` option heuristically (based on the association name).
+Most associations with standard names will be supported. However, associations
+that contain the following options will not have their inverses set
+automatically:
+
+* :conditions
+* :through
+* :polymorphic
+* :foreign_key
+
Detailed Association Reference
------------------------------
@@ -572,12 +718,13 @@ The `belongs_to` association creates a one-to-one match with another model. In d
#### Methods Added by `belongs_to`
-When you declare a `belongs_to` association, the declaring class automatically gains four methods related to the association:
+When you declare a `belongs_to` association, the declaring class automatically gains five methods related to the association:
* `association(force_reload = false)`
* `association=(associate)`
* `build_association(attributes = {})`
* `create_association(attributes = {})`
+* `create_association!(attributes = {})`
In all of these methods, `association` is replaced with the symbol passed as the first argument to `belongs_to`. For example, given the declaration:
@@ -594,6 +741,7 @@ customer
customer=
build_customer
create_customer
+create_customer!
```
NOTE: When initializing a new `has_one` or `belongs_to` association you must use the `build_` prefix to build the association, rather than the `association.build` method that would be used for `has_many` or `has_and_belongs_to_many` associations. To create one, use the `create_` prefix.
@@ -621,8 +769,8 @@ The `association=` method assigns an associated object to this object. Behind th
The `build_association` method returns a new object of the associated type. This object will be instantiated from the passed attributes, and the link through this object's foreign key will be set, but the associated object will _not_ yet be saved.
```ruby
-@customer = @order.build_customer(:customer_number => 123,
- :customer_name => "John Doe")
+@customer = @order.build_customer(customer_number: 123,
+ customer_name: "John Doe")
```
##### `create_association(attributes = {})`
@@ -630,19 +778,23 @@ The `build_association` method returns a new object of the associated type. This
The `create_association` method returns a new object of the associated type. This object will be instantiated from the passed attributes, the link through this object's foreign key will be set, and, once it passes all of the validations specified on the associated model, the associated object _will_ be saved.
```ruby
-@customer = @order.create_customer(:customer_number => 123,
- :customer_name => "John Doe")
+@customer = @order.create_customer(customer_number: 123,
+ customer_name: "John Doe")
```
+##### `create_association!(attributes = {})`
+
+Does the same as `create_association` above, but raises `ActiveRecord::RecordInvalid` if the record is invalid.
+
#### 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 and scope blocks 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 association uses two such options:
```ruby
class Order < ActiveRecord::Base
- belongs_to :customer, :dependent => :destroy,
- :counter_cache => true
+ belongs_to :customer, dependent: :destroy,
+ counter_cache: true
end
```
@@ -668,7 +820,7 @@ If the name of the other model cannot be derived from the association name, you
```ruby
class Order < ActiveRecord::Base
- belongs_to :customer, :class_name => "Patron"
+ belongs_to :customer, class_name: "Patron"
end
```
@@ -689,7 +841,7 @@ With these declarations, asking for the value of `@customer.orders.size` require
```ruby
class Order < ActiveRecord::Base
- belongs_to :customer, :counter_cache => true
+ belongs_to :customer, counter_cache: true
end
class Customer < ActiveRecord::Base
has_many :orders
@@ -702,7 +854,7 @@ Although the `:counter_cache` option is specified on the model that includes the
```ruby
class Order < ActiveRecord::Base
- belongs_to :customer, :counter_cache => :count_of_orders
+ belongs_to :customer, counter_cache: :count_of_orders
end
class Customer < ActiveRecord::Base
has_many :orders
@@ -713,7 +865,7 @@ Counter cache columns are added to the containing model's list of read-only attr
##### `: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 `: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 `:restrict`, then attempting to delete this object will result in a `ActiveRecord::DeleteRestrictionError` if there are any associated objects.
WARNING: You should not specify this option on a `belongs_to` association that is connected with a `has_many` association on the other class. Doing so can lead to orphaned records in your database.
@@ -723,8 +875,8 @@ By convention, Rails assumes that the column used to hold the foreign key on thi
```ruby
class Order < ActiveRecord::Base
- belongs_to :customer, :class_name => "Patron",
- :foreign_key => "patron_id"
+ belongs_to :customer, class_name: "Patron",
+ foreign_key: "patron_id"
end
```
@@ -736,11 +888,11 @@ The `:inverse_of` option specifies the name of the `has_many` or `has_one` assoc
```ruby
class Customer < ActiveRecord::Base
- has_many :orders, :inverse_of => :customer
+ has_many :orders, inverse_of: :customer
end
class Order < ActiveRecord::Base
- belongs_to :customer, :inverse_of => :orders
+ belongs_to :customer, inverse_of: :orders
end
```
@@ -754,7 +906,7 @@ If you set the `:touch` option to `:true`, then the `updated_at` or `updated_on`
```ruby
class Order < ActiveRecord::Base
- belongs_to :customer, :touch => true
+ belongs_to :customer, touch: true
end
class Customer < ActiveRecord::Base
@@ -766,7 +918,7 @@ In this case, saving or destroying an order will update the timestamp on the ass
```ruby
class Order < ActiveRecord::Base
- belongs_to :customer, :touch => :orders_updated_at
+ belongs_to :customer, touch: :orders_updated_at
end
```
@@ -780,8 +932,8 @@ There may be times when you wish to customize the query used by `belongs_to`. Su
```ruby
class Order < ActiveRecord::Base
- belongs_to :customer, -> { where :active => true },
- :dependent => :destroy
+ belongs_to :customer, -> { where active: true },
+ dependent: :destroy
end
```
@@ -798,13 +950,13 @@ The `where` method lets you specify the conditions that the associated object mu
```ruby
class Order < ActiveRecord::Base
- belongs_to :customer, -> { where :active => true }
+ belongs_to :customer, -> { where active: true }
end
```
##### `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:
+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 LineItem < ActiveRecord::Base
@@ -870,12 +1022,13 @@ The `has_one` association creates a one-to-one match with another model. In data
#### Methods Added by `has_one`
-When you declare a `has_one` association, the declaring class automatically gains four methods related to the association:
+When you declare a `has_one` association, the declaring class automatically gains five methods related to the association:
* `association(force_reload = false)`
* `association=(associate)`
* `build_association(attributes = {})`
* `create_association(attributes = {})`
+* `create_association!(attributes = {})`
In all of these methods, `association` is replaced with the symbol passed as the first argument to `has_one`. For example, given the declaration:
@@ -892,6 +1045,7 @@ account
account=
build_account
create_account
+create_account!
```
NOTE: When initializing a new `has_one` or `belongs_to` association you must use the `build_` prefix to build the association, rather than the `association.build` method that would be used for `has_many` or `has_and_belongs_to_many` associations. To create one, use the `create_` prefix.
@@ -919,7 +1073,7 @@ The `association=` method assigns an associated object to this object. Behind th
The `build_association` method returns a new object of the associated type. This object will be instantiated from the passed attributes, and the link through its foreign key will be set, but the associated object will _not_ yet be saved.
```ruby
-@account = @supplier.build_account(:terms => "Net 30")
+@account = @supplier.build_account(terms: "Net 30")
```
##### `create_association(attributes = {})`
@@ -927,16 +1081,20 @@ The `build_association` method returns a new object of the associated type. This
The `create_association` method returns a new object of the associated type. This object will be instantiated from the passed attributes, the link through its foreign key will be set, and, once it passes all of the validations specified on the associated model, the associated object _will_ be saved.
```ruby
-@account = @supplier.create_account(:terms => "Net 30")
+@account = @supplier.create_account(terms: "Net 30")
```
+##### `create_association!(attributes = {})`
+
+Does the same as `create_association` above, but raises `ActiveRecord::RecordInvalid` if the record is invalid.
+
#### Options for `has_one`
-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_one` 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 `has_one` association reference. Such customizations can easily be accomplished by passing options when you create the association. For example, this association uses two such options:
```ruby
class Supplier < ActiveRecord::Base
- has_one :account, :class_name => "Billing", :dependent => :nullify
+ has_one :account, class_name: "Billing", dependent: :nullify
end
```
@@ -968,7 +1126,7 @@ If the name of the other model cannot be derived from the association name, you
```ruby
class Supplier < ActiveRecord::Base
- has_one :account, :class_name => "Billing"
+ has_one :account, class_name: "Billing"
end
```
@@ -977,18 +1135,24 @@ end
Controls what happens to the associated object when its owner is destroyed:
* `:destroy` causes the associated object to also be destroyed
-* `:delete` causes the asssociated object to be deleted directly from the database (so callbacks will not execute)
+* `:delete` causes the associated object to be deleted directly from the database (so callbacks will not execute)
* `:nullify` causes the foreign key to be set to `NULL`. Callbacks are not executed.
* `:restrict_with_exception` causes an exception to be raised if there is an associated record
* `:restrict_with_error` causes an error to be added to the owner if there is an associated object
+It's necessary not to set or leave `:nullify` option for those associations
+that have `NOT NULL` database constraints. If you don't set `dependent` to
+destroy such associations you won't be able to change the associated object
+because initial associated object foreign key will be set to unallowed `NULL`
+value.
+
##### `: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 Supplier < ActiveRecord::Base
- has_one :account, :foreign_key => "supp_id"
+ has_one :account, foreign_key: "supp_id"
end
```
@@ -1000,11 +1164,11 @@ The `:inverse_of` option specifies the name of the `belongs_to` association that
```ruby
class Supplier < ActiveRecord::Base
- has_one :account, :inverse_of => :supplier
+ has_one :account, inverse_of: :supplier
end
class Account < ActiveRecord::Base
- belongs_to :supplier, :inverse_of => :account
+ belongs_to :supplier, inverse_of: :account
end
```
@@ -1034,7 +1198,7 @@ There may be times when you wish to customize the query used by `has_one`. Such
```ruby
class Supplier < ActiveRecord::Base
- has_one :account, -> { where :active => true }
+ has_one :account, -> { where active: true }
end
```
@@ -1125,7 +1289,7 @@ The `has_many` association creates a one-to-many relationship with another model
#### Methods Added by `has_many`
-When you declare a `has_many` association, the declaring class automatically gains 13 methods related to the association:
+When you declare a `has_many` association, the declaring class automatically gains 16 methods related to the association:
* `collection(force_reload = false)`
* `collection<<(object, ...)`
@@ -1142,8 +1306,9 @@ When you declare a `has_many` association, the declaring class automatically gai
* `collection.exists?(...)`
* `collection.build(attributes = {}, ...)`
* `collection.create(attributes = {})`
+* `collection.create!(attributes = {})`
-In all of these methods, `collection` is replaced with the symbol passed as the first argument to `has_many`, and `collection_singular` is replaced with the singularized version of that symbol.. For example, given the declaration:
+In all of these methods, `collection` is replaced with the symbol passed as the first argument to `has_many`, and `collection_singular` is replaced with the singularized version of that symbol. For example, given the declaration:
```ruby
class Customer < ActiveRecord::Base
@@ -1169,6 +1334,7 @@ orders.where(...)
orders.exists?(...)
orders.build(attributes = {}, ...)
orders.create(attributes = {})
+orders.create!(attributes = {})
```
##### `collection(force_reload = false)`
@@ -1195,7 +1361,7 @@ The `collection.delete` method removes one or more objects from the collection b
@customer.orders.delete(@order1)
```
-WARNING: Additionally, objects will be destroyed if they're associated with `:dependent => :destroy`, and deleted if they're associated with `:dependent => :delete_all`.
+WARNING: Additionally, objects will be destroyed if they're associated with `dependent: :destroy`, and deleted if they're associated with `dependent: :delete_all`.
##### `collection.destroy(object, ...)`
@@ -1225,7 +1391,7 @@ The `collection_singular_ids=` method makes the collection contain only the obje
##### `collection.clear`
-The `collection.clear` method removes every object from the collection. This destroys the associated objects if they are associated with `:dependent => :destroy`, deletes them directly from the database if `:dependent => :delete_all`, and otherwise sets their foreign keys to `NULL`.
+The `collection.clear` method removes every object from the collection. This destroys the associated objects if they are associated with `dependent: :destroy`, deletes them directly from the database if `dependent: :delete_all`, and otherwise sets their foreign keys to `NULL`.
##### `collection.empty?`
@@ -1258,7 +1424,7 @@ The `collection.find` method finds objects within the collection. It uses the sa
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.
```ruby
-@open_orders = @customer.orders.where(:open => true) # No query yet
+@open_orders = @customer.orders.where(open: true) # No query yet
@open_order = @open_orders.first # Now the database will be queried
```
@@ -1271,8 +1437,8 @@ The `collection.exists?` method checks whether an object meeting the supplied co
The `collection.build` method returns one or more new objects of the associated type. These objects will be instantiated from the passed attributes, and the link through their foreign key will be created, but the associated objects will _not_ yet be saved.
```ruby
-@order = @customer.orders.build(:order_date => Time.now,
- :order_number => "A12345")
+@order = @customer.orders.build(order_date: Time.now,
+ order_number: "A12345")
```
##### `collection.create(attributes = {})`
@@ -1280,17 +1446,21 @@ The `collection.build` method returns one or more new objects of the associated
The `collection.create` method returns a new object of the associated type. This object will be instantiated from the passed attributes, the link through its foreign key will be created, and, once it passes all of the validations specified on the associated model, the associated object _will_ be saved.
```ruby
-@order = @customer.orders.create(:order_date => Time.now,
- :order_number => "A12345")
+@order = @customer.orders.create(order_date: Time.now,
+ order_number: "A12345")
```
+##### `collection.create!(attributes = {})`
+
+Does the same as `collection.create` above, but raises `ActiveRecord::RecordInvalid` if the record is invalid.
+
#### Options for `has_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_many` 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 `has_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:
```ruby
class Customer < ActiveRecord::Base
- has_many :orders, :dependent => :delete_all, :validate => :false
+ has_many :orders, dependent: :delete_all, validate: :false
end
```
@@ -1322,7 +1492,7 @@ If the name of the other model cannot be derived from the association name, you
```ruby
class Customer < ActiveRecord::Base
- has_many :orders, :class_name => "Transaction"
+ has_many :orders, class_name: "Transaction"
end
```
@@ -1331,7 +1501,7 @@ end
Controls what happens to the associated objects when their owner is destroyed:
* `:destroy` causes all the associated objects to also be destroyed
-* `:delete_all` causes all the asssociated objects to be deleted directly from the database (so callbacks will not execute)
+* `:delete_all` causes all the associated objects to be deleted directly from the database (so callbacks will not execute)
* `:nullify` causes the foreign keys to be set to `NULL`. Callbacks are not executed.
* `:restrict_with_exception` causes an exception to be raised if there are any associated records
* `:restrict_with_error` causes an error to be added to the owner if there are any associated objects
@@ -1344,7 +1514,7 @@ By convention, Rails assumes that the column used to hold the foreign key on the
```ruby
class Customer < ActiveRecord::Base
- has_many :orders, :foreign_key => "cust_id"
+ has_many :orders, foreign_key: "cust_id"
end
```
@@ -1356,11 +1526,11 @@ The `:inverse_of` option specifies the name of the `belongs_to` association that
```ruby
class Customer < ActiveRecord::Base
- has_many :orders, :inverse_of => :customer
+ has_many :orders, inverse_of: :customer
end
class Order < ActiveRecord::Base
- belongs_to :customer, :inverse_of => :orders
+ belongs_to :customer, inverse_of: :orders
end
```
@@ -1368,6 +1538,20 @@ end
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.
+Let's say that `users` table has `id` as the primary_key but it also has
+`guid` column. And the requirement is that `todos` table should hold
+`guid` column value and not `id` value. This can be achieved like this
+
+```ruby
+class User < ActiveRecord::Base
+ has_many :todos, primary_key: :guid
+end
+```
+
+Now if we execute `@user.todos.create` then `@todo` record will have
+`user_id` value as the `guid` value of `@user`.
+
+
##### `: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.
@@ -1390,7 +1574,7 @@ There may be times when you wish to customize the query used by `has_many`. Such
```ruby
class Customer < ActiveRecord::Base
- has_many :orders, -> { where :processed => true }
+ has_many :orders, -> { where processed: true }
end
```
@@ -1414,7 +1598,7 @@ The `where` method lets you specify the conditions that the associated object mu
```ruby
class Customer < ActiveRecord::Base
has_many :confirmed_orders, -> { where "confirmed = 1" },
- :class_name => "Order"
+ class_name: "Order"
end
```
@@ -1422,8 +1606,8 @@ You can also set conditions via a hash:
```ruby
class Customer < ActiveRecord::Base
- has_many :confirmed_orders, -> { where :confirmed => true },
- :class_name => "Order"
+ has_many :confirmed_orders, -> { where confirmed: true },
+ class_name: "Order"
end
```
@@ -1440,7 +1624,7 @@ The `group` method supplies an attribute name to group the result set by, using
```ruby
class Customer < ActiveRecord::Base
has_many :line_items, -> { group 'orders.id' },
- :through => :orders
+ through: :orders
end
```
@@ -1488,7 +1672,7 @@ The `limit` method lets you restrict the total number of objects that will be fe
class Customer < ActiveRecord::Base
has_many :recent_orders,
-> { order('order_date desc').limit(100) },
- :class_name => "Order",
+ class_name: "Order",
end
```
@@ -1516,43 +1700,67 @@ The `select` method lets you override the SQL `SELECT` clause that is used to re
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.
-##### `uniq`
+##### `distinct`
-Use the `uniq` method to keep the collection free of duplicates. This is mostly useful together with the `:through` option.
+Use the `distinct` method to keep the collection free of duplicates. This is
+mostly useful together with the `:through` option.
```ruby
class Person < ActiveRecord::Base
has_many :readings
- has_many :posts, :through => :readings
+ has_many :posts, through: :readings
end
-person = Person.create(:name => 'john')
-post = Post.create(:name => 'a1')
+person = Person.create(name: 'John')
+post = Post.create(name: 'a1')
person.posts << post
person.posts << post
person.posts.inspect # => [#<Post id: 5, name: "a1">, #<Post id: 5, name: "a1">]
Reading.all.inspect # => [#<Reading id: 12, person_id: 5, post_id: 5>, #<Reading id: 13, person_id: 5, post_id: 5>]
```
-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.
+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`:
+Now let's set `distinct`:
```ruby
class Person
has_many :readings
- has_many :posts, -> { uniq }, :through => :readings
+ has_many :posts, -> { distinct }, through: :readings
end
-person = Person.create(:name => 'honda')
-post = Post.create(:name => 'a1')
+person = Person.create(name: 'Honda')
+post = Post.create(name: 'a1')
person.posts << post
person.posts << post
person.posts.inspect # => [#<Post id: 7, name: "a1">]
Reading.all.inspect # => [#<Reading id: 16, person_id: 7, post_id: 7>, #<Reading id: 17, person_id: 7, post_id: 7>]
```
-In the above case there are still two readings. However `person.posts` shows only one post because the collection loads only unique records.
+In the above case there are still two readings. However `person.posts` shows
+only one post because the collection loads only unique records.
+
+If you want to make sure that, upon insertion, all of the records in the
+persisted association are distinct (so that you can be sure that when you
+inspect the association that you will never find duplicate records), you should
+add a unique index on the table itself. For example, if you have a table named
+`person_posts` and you want to make sure all the posts are unique, you could
+add the following in a migration:
+
+```ruby
+add_index :person_posts, :post, unique: true
+```
+
+Note that checking for uniqueness using something like `include?` is subject
+to race conditions. Do not attempt to use `include?` to enforce distinctness
+in an association. For instance, using the post example from above, the
+following code would be racy because multiple users could be attempting this
+at the same time:
+
+```ruby
+person.posts << post unless person.posts.include?(post)
+```
#### When are Objects Saved?
@@ -1570,7 +1778,7 @@ The `has_and_belongs_to_many` association creates a many-to-many relationship wi
#### Methods Added by `has_and_belongs_to_many`
-When you declare a `has_and_belongs_to_many` association, the declaring class automatically gains 13 methods related to the association:
+When you declare a `has_and_belongs_to_many` association, the declaring class automatically gains 16 methods related to the association:
* `collection(force_reload = false)`
* `collection<<(object, ...)`
@@ -1587,6 +1795,7 @@ When you declare a `has_and_belongs_to_many` association, the declaring class au
* `collection.exists?(...)`
* `collection.build(attributes = {})`
* `collection.create(attributes = {})`
+* `collection.create!(attributes = {})`
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:
@@ -1614,6 +1823,7 @@ assemblies.where(...)
assemblies.exists?(...)
assemblies.build(attributes = {}, ...)
assemblies.create(attributes = {})
+assemblies.create!(attributes = {})
```
##### Additional Column Methods
@@ -1722,8 +1932,7 @@ The `collection.exists?` method checks whether an object meeting the supplied co
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.
```ruby
-@assembly = @part.assemblies.build(
- {:assembly_name => "Transmission housing"})
+@assembly = @part.assemblies.build({assembly_name: "Transmission housing"})
```
##### `collection.create(attributes = {})`
@@ -1731,18 +1940,21 @@ The `collection.build` method returns a new object of the associated type. This
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.
```ruby
-@assembly = @part.assemblies.create(
- {:assembly_name => "Transmission housing"})
+@assembly = @part.assemblies.create({assembly_name: "Transmission housing"})
```
+##### `collection.create!(attributes = {})`
+
+Does the same as `collection.create`, but raises `ActiveRecord::RecordInvalid` if the record is invalid.
+
#### 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 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 `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:
```ruby
class Parts < ActiveRecord::Base
- has_and_belongs_to_many :assemblies, :uniq => true,
- :read_only => true
+ has_and_belongs_to_many :assemblies, autosave: true,
+ readonly: true
end
```
@@ -1754,6 +1966,7 @@ The `has_and_belongs_to_many` association supports these options:
* `:foreign_key`
* `:join_table`
* `:validate`
+* `:readonly`
##### `:association_foreign_key`
@@ -1763,9 +1976,10 @@ TIP: The `:foreign_key` and `:association_foreign_key` options are useful when s
```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"
+ has_and_belongs_to_many :friends,
+ class_name: "User",
+ foreign_key: "this_user_id",
+ association_foreign_key: "other_user_id"
end
```
@@ -1779,7 +1993,7 @@ If the name of the other model cannot be derived from the association name, you
```ruby
class Parts < ActiveRecord::Base
- has_and_belongs_to_many :assemblies, :class_name => "Gadget"
+ has_and_belongs_to_many :assemblies, class_name: "Gadget"
end
```
@@ -1789,9 +2003,10 @@ By convention, Rails assumes that the column in the join table used to hold the
```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"
+ has_and_belongs_to_many :friends,
+ class_name: "User",
+ foreign_key: "this_user_id",
+ association_foreign_key: "other_user_id"
end
```
@@ -1809,7 +2024,7 @@ There may be times when you wish to customize the query used by `has_and_belongs
```ruby
class Parts < ActiveRecord::Base
- has_and_belongs_to_many :assemblies, -> { where :active => true }
+ has_and_belongs_to_many :assemblies, -> { where active: true }
end
```
@@ -1842,7 +2057,7 @@ You can also set conditions via a hash:
```ruby
class Parts < ActiveRecord::Base
has_and_belongs_to_many :assemblies,
- -> { where :factory => 'Seattle' }
+ -> { where factory: 'Seattle' }
end
```
@@ -1929,7 +2144,7 @@ You define association callbacks by adding options to the association declaratio
```ruby
class Customer < ActiveRecord::Base
- has_many :orders, :before_add => :check_credit_limit
+ has_many :orders, before_add: :check_credit_limit
def check_credit_limit(order)
...
@@ -1944,7 +2159,7 @@ You can stack callbacks on a single event by passing them as an array:
```ruby
class Customer < ActiveRecord::Base
has_many :orders,
- :before_add => [:check_credit_limit, :calculate_shipping_charges]
+ before_add: [:check_credit_limit, :calculate_shipping_charges]
def check_credit_limit(order)
...
@@ -1966,7 +2181,7 @@ You're not limited to the functionality that Rails automatically builds into ass
class Customer < ActiveRecord::Base
has_many :orders do
def find_by_order_prefix(order_number)
- find_by_region_id(order_number[0..2])
+ find_by(region_id: order_number[0..2])
end
end
end