Skip to content

Commit 69c86f9

Browse files
Ridhwanap8rizwanrezaMatheusRichmstroming
authored
[RF-DOCS]Active Record Associations Guide [ci-skip] (rails#52523)
* The images used to show the relationships of the different types of associations have both the table declarations, as well as a code sample, but the code sample is also in the guide. We could probably simplify the images by cutting off the code samples from them and leaving them in the guide code. * belongs_to section mentions bi-directional association and links to it within the same guide, but doesn't do the same for has_one and has_many, mentioned right after in the same paragraph. * There's a note about using bigint :supplier_id in the section between belongs_to and has_one, but up until that point it's always been using belongs_to in migrations... it's probably something that doesn't need to be in this area of the guide. * The has_many :through vs has_and_belongs_to_many section ends with a composite keys mention, we could link to the new guide there. * Associations between models with composite PKs may be simplified. * One example in bi-directional associations mentions Book belongs_to :writer, but then uses book.author a few lines below, which is incorrect. * STI section could be expanded, it's very useful in certain situations. * Add more info and make it clear * Group sections better * Amend the References section to be integrated with associations * Abstract and remove duplications for options and scopes Co-authored-by: Petrik de Heus <petrik@deheus.net> Co-authored-by: Rizwan Reza <github@rizwanreza.com> Co-authored-by: Matheus Richard <matheusrichardt@gmail.com> Co-authored-by: Mike Stroming <mstrom81@gmail.com> Co-authored-by: Harriet Oughton <harrietoughton@gmail.com>
1 parent dd3f743 commit 69c86f9

10 files changed

+2297
-2057
lines changed
Loading
Loading
Loading
Loading
Loading
Loading
Loading

guides/source/active_record_composite_primary_keys.md

+41-16
Original file line numberDiff line numberDiff line change
@@ -123,9 +123,14 @@ guide to learn more.
123123
Associations between Models with Composite Primary Keys
124124
-------------------------------------------------------
125125

126-
Rails is often able to infer the primary key - foreign key information between
127-
associated models with composite primary keys without needing extra information.
128-
Take the following example:
126+
Rails can often infer the primary key-foreign key relationships between
127+
associated models. However, when dealing with composite primary keys, Rails
128+
typically defaults to using only part of the composite key, usually the `id`
129+
column, unless explicitly instructed otherwise. This default behavior only works
130+
if the model's composite primary key contains the `:id` column, _and_ the column
131+
is unique for all records.
132+
133+
Consider the following example:
129134

130135
```ruby
131136
class Order < ApplicationRecord
@@ -138,29 +143,40 @@ class Book < ApplicationRecord
138143
end
139144
```
140145

141-
Here, Rails assumes that the `:id` column should be used as the primary key for
142-
the association between an order and its books, just as with a regular
143-
`has_many` / `belongs_to` association. It will infer that the foreign key column
144-
on the `books` table is `:order_id`. Accessing a book's order:
146+
In this setup, `Order` has a composite primary key consisting of `[:shop_id,
147+
:id]`, and `Book` belongs to `Order`. Rails will assume that the `:id` column
148+
should be used as the primary key for the association between an order and its
149+
books. It will infer that the foreign key column on the books table is
150+
`:order_id`.
151+
152+
Below we create an `Order` and a `Book` associated with it:
145153

146154
```ruby
147155
order = Order.create!(id: [1, 2], status: "pending")
148156
book = order.books.create!(title: "A Cool Book")
157+
```
149158

159+
To access the book's order, we reload the association:
160+
161+
```ruby
150162
book.reload.order
151163
```
152164

153-
will generate the following SQL to access the order:
165+
When doing so, Rails will generate the following SQL to access the order:
154166

155167
```sql
156168
SELECT * FROM orders WHERE id = 2
157169
```
158170

159-
This only works if the model's composite primary key contains the `:id` column,
160-
_and_ the column is unique for all records. In order to use the full composite
161-
primary key in associations, set the `foreign_key:` option on the
162-
association. This option specifies a composite foreign key on the association,
163-
meaning that all columns in the foreign key will be used to query the
171+
You can see that Rails uses the order's `id` in its query, rather than both the
172+
`shop_id` and the `id`. In this case, the `id` is sufficient because the model's
173+
composite primary key does in fact contain the `:id` column, _and_ the column is
174+
unique for all records.
175+
176+
However, if the above requirements are not met or you would like to use the full
177+
composite primary key in associations, you can set the `foreign_key:` option on
178+
the association. This option specifies a composite foreign key on the
179+
association; all columns in the foreign key will be used when querying the
164180
associated record(s). For example:
165181

166182
```ruby
@@ -174,16 +190,25 @@ class Book < ApplicationRecord
174190
end
175191
```
176192

177-
Accessing a book's author:
193+
In this setup, `Author` has a composite primary key consisting of `[:first_name,
194+
:last_name]`, and `Book` belongs to `Author` with a composite foreign key
195+
`[:author_first_name, :author_last_name]`.
196+
197+
Create an `Author` and a `Book` associated with it:
178198

179199
```ruby
180200
author = Author.create!(first_name: "Jane", last_name: "Doe")
181-
book = author.books.create!(title: "A Cool Book")
201+
book = author.books.create!(title: "A Cool Book", author_first_name: "Jane", author_last_name: "Doe")
202+
```
182203

204+
To access the book's author, we reload the association:
205+
206+
```ruby
183207
book.reload.author
184208
```
185209

186-
will use `:first_name` _and_ `:last_name` in the SQL query:
210+
Rails will now use the `:first_name` _and_ `:last_name` from the composite
211+
primary key in the SQL query:
187212

188213
```sql
189214
SELECT * FROM authors WHERE first_name = 'Jane' AND last_name = 'Doe'

guides/source/active_record_migrations.md

+11-1
Original file line numberDiff line numberDiff line change
@@ -559,9 +559,19 @@ create_join_table :products, :categories, column_options: { null: true }
559559
```
560560

561561
By default, the name of the join table comes from the union of the first two
562-
arguments provided to create_join_table, in alphabetical order. In this case,
562+
arguments provided to create_join_table, in lexical order. In this case,
563563
the table would be named `categories_products`.
564564

565+
WARNING: The precedence between model names is calculated using the `<=>`
566+
operator for `String`. This means that if the strings are of different lengths,
567+
and the strings are equal when compared up to the shortest length, then the
568+
longer string is considered of higher lexical precedence than the shorter one.
569+
For example, one would expect the tables "paper_boxes" and "papers" to generate
570+
a join table name of "papers_paper_boxes" because of the length of the name
571+
"paper_boxes", but it in fact generates a join table name of
572+
"paper_boxes_papers" (because the underscore '\_' is lexicographically _less_
573+
than 's' in common encodings).
574+
565575
To customize the name of the table, provide a `:table_name` option:
566576

567577
```ruby

0 commit comments

Comments
 (0)