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.md90
1 files changed, 69 insertions, 21 deletions
diff --git a/guides/source/association_basics.md b/guides/source/association_basics.md
index 16a5241319..91b268d766 100644
--- a/guides/source/association_basics.md
+++ b/guides/source/association_basics.md
@@ -40,7 +40,7 @@ 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
@@ -69,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`
@@ -261,7 +261,10 @@ 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
@@ -337,7 +340,7 @@ class CreateAssembliesAndParts < ActiveRecord::Migration
t.timestamps
end
- create_table :assemblies_parts do |t|
+ create_table :assemblies_parts, id: false do |t|
t.belongs_to :assembly
t.belongs_to :part
end
@@ -721,6 +724,7 @@ When you declare a `belongs_to` association, the declaring class automatically g
* `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:
@@ -737,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.
@@ -777,6 +782,10 @@ The `create_association` method returns a new object of the associated type. Thi
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`
@@ -947,7 +956,7 @@ 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
@@ -1019,6 +1028,7 @@ When you declare a `has_one` association, the declaring class automatically gain
* `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:
@@ -1035,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.
@@ -1073,6 +1084,10 @@ The `create_association` method returns a new object of the associated type. Thi
@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 association uses two such options:
@@ -1125,6 +1140,12 @@ Controls what happens to the associated object when its owner is destroyed:
* `: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:
@@ -1285,6 +1306,7 @@ 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:
@@ -1312,6 +1334,7 @@ orders.where(...)
orders.exists?(...)
orders.build(attributes = {}, ...)
orders.create(attributes = {})
+orders.create!(attributes = {})
```
##### `collection(force_reload = false)`
@@ -1427,6 +1450,10 @@ The `collection.create` method returns a new object of the associated type. This
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 association uses two such options:
@@ -1511,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.
@@ -1678,7 +1719,7 @@ 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
+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 `distinct`:
@@ -1697,24 +1738,24 @@ 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
+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
+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
+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
+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
@@ -1754,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:
@@ -1781,6 +1823,7 @@ assemblies.where(...)
assemblies.exists?(...)
assemblies.build(attributes = {}, ...)
assemblies.create(attributes = {})
+assemblies.create!(attributes = {})
```
##### Additional Column Methods
@@ -1900,14 +1943,18 @@ The `collection.create` method returns a new object of the associated type. This
@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 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
```
@@ -1919,6 +1966,7 @@ The `has_and_belongs_to_many` association supports these options:
* `:foreign_key`
* `:join_table`
* `:validate`
+* `:readonly`
##### `:association_foreign_key`
@@ -1928,7 +1976,7 @@ TIP: The `:foreign_key` and `:association_foreign_key` options are useful when s
```ruby
class User < ActiveRecord::Base
- has_and_belongs_to_many :friends,
+ has_and_belongs_to_many :friends,
class_name: "User",
foreign_key: "this_user_id",
association_foreign_key: "other_user_id"
@@ -2133,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