* Reference consistency check correction
By default all belongs_to relations are set to required, and required means Rails checks the reference consistency. That sentence is correct only if the optional is set to true, then in this case Rails not only allows this field to be null but also it does not check the reference consistency. But this is not the default behavior.
Co-authored-by: Eileen M. Uchitelle <eileencodes@users.noreply.github.com>
Since #43138, each config setting has its own linkable section in the
configuration guide.
This commit links config settings throughout the guides to their
sections in the configuration guide.
Counter cache can hold stale value if user changes primary key's value.
This caveat is not mentioned in guides, but according to #16159
comments it should be.
I remember being confused about what exactly association inverses would
do for me. This guide helped, but it leaves out some use cases. I'm hoping
that having all these use cases documented in one place with code
examples for each will make it easier for folks to understand why
they might want to set `:inverse_of` when Rails can't infer it.
Specifically, this commit:
* Adds an example explicitly demonstrating that all the `Author` objects
are the same, and that no additional queries are executed.
* Preserves the example around preventing inconsistent data (although
replaces the single-letter variable names)
* Adds an example around autosaving, which I'm not sure is explicitly
documented elsewhere
* Adds an example around validations, linking to the relevant sections
of the validation guide where we mention needing to set the
`:inverse_of` for these validations
This commit also adds links from the `:inverse_of` sections back up to
the Bi-directional associations sections, hopefully making those
`:inverse_of` sections clearer.
Background
---
I recently noticed we had a number of associations in GitHub that would
benefit from having `inverse_of` set, and so I began adding them. I
ended up adding them to virtually every association with a scope, at
which point I wondered whether Rails might be able to automatically find
these inverses for us.
For GitHub, the changes in this commit end up automatically adding
`inverse_of` to 171 of associations that were missing it.
My understanding is that we do not automatically detect `inverse_of` for
associations with scopes because the scopes could exclude the records we
are trying to inverse from. But I think that should only matter if there
is a scope on the inverse side, not on the association itself.
For example:
Scope on has_many
----
```rb
class Post < ActiveRecord::Base
has_many :comments, -> { visible }
end
class Comment < ActiveRecord::Base
belongs_to :post
scope :visible, -> { where(visible: true) }
scope :hidden, -> { where(visible: false) }
end
post = Post.create!
comment = post.comments.hidden.create!
assert comment.post
```
This code leaves `post.comments` in sort of a weird state, since it
includes a comment that the association would filter out. But that's
true regardless of the changes in this commit.
Regardless of whether the comments association has an inverse,
`comment.post` will return the post. The difference is that when
`inverse_of` is set we use the existing post we have in memory, rather
than loading it again. If there is a downside to having the `inverse_of`
automatically set here I'm not seeing it.
Scope on belongs_to
----
```rb
class Post < ActiveRecord::Base
has_many :comments
scope :visible, -> { where(visible: true) }
scope :hidden, -> { where(visible: false) }
end
class Comment < ActiveRecord::Base
belongs_to :post, -> { visible }
end
post = Post.hidden.create!
comment = post.comments.create!
assert_nil comment.post
```
This example is a different story. We don't want to automatically infer
the inverse here because that would change the behavior of
`comment.post`. It should return `nil`, since it's scoped to visible
posts while this one is hidden.
This behavior was not well tested, so this commit adds a test to
ensure we haven't changed it.
Changes
---
This commit changes `can_find_inverse_of_automatically` to allow us to
automatically detect `inverse_of` when there is a scope on the
association, but not when there is a scope on the potential inverse
association. (`can_find_inverse_of_automatically` gets called first with
the association's reflection, then if it returns true we attempt to find
the inverse reflection, and finally we call the method again with the
inverse reflection to ensure we can really use it.)
Since this is a breaking change—specifically in places where code may
have relied on a missing `inverse_of` causing fresh copies of a record
to be loaded—we've placed it behind the `automatic_scope_inversing` flag
(whose name was inspired by `has_many_inversing`). It is set to true for
new applications via framework defaults.
Testing
---
In addition to the inverse association tests, this commit also adds some
cases to a few tests related to preloading. They are basically
duplicates of existing tests, but with lower query counts.
Testing this change with GitHub, the bulk of the failing tests were
related to lower query counts. There were additionally 3 places (2 in
tests and one in application code) where we relied on missing
`inverse_of` causing fresh copies of a record to be loaded.
There's still one Rails test that wouldn't pass if we ran the whole
suite with `automatic_scope_inversing = true`. It's related to
`TaggedPost`, which changes the polymorphic type from the base class
`Post` to the subclass `TaggedPost`.
```rb
class TaggedPost < Post
has_many :taggings, -> { rewhere(taggable_type: "TaggedPost") }, as: :taggable
end
```
Setting the inverse doesn't work because it ends up changing the type
back to `Post`, something like this:
```rb
post = TaggedPost.new
tagging = post.taggings.new
puts tagging.taggable_type
=> TaggedPost
tagging.taggable = post
puts tagging.taggable_type
=> Post
```
I think this is an acceptable change, given that it's a fairly specific
scenario, and is sort of at odds with the way polymorphic associations
are meant to work (they are meant to contain the base class, not the
subclass). If someone is relying on this specific behavior they can
still either keep `automatic_scope_inversing` set to false, or they can
add `inverse_of: false` to the association.
I haven't found any other cases where having the `inverse_of` would
cause problems like this.
Co-authored-by: Chris Bloom <chrisbloom7@gmail.com>
Permit checking whether a belongs_to association has been pointed to a new target record in the previous save and whether it will point to a new target record in the next save.
post.category # => #<Category id: 1, name: "Ruby">
post.category = Category.second # => #<Category id: 2, name: "Programming">
post.category_changed? # => true
post.category_previously_changed? # => false
post.save!
post.category_changed? # => false
post.category_previously_changed? # => true
Migration version references has been updated 2 times in less than 3
weeks (#41894, #42113).
I'd not want to receive the same tweaks in the near future.
* Document Destroy Async
Motivation:
- Add docs for Destroy async. I think I probably need to add
information about setting up active job, but I am not sure where we
want this, so I am putting this together to start conversation.
Related Issues:
- #41093
* Active Job not ActiveJob
* Fix some spelling issues
[Cory Gwin, Rafael Mendonça França, Eileen M. Uchitelle, Henrik Nyh]
This links the first mention of each method to its API documentation,
similar to a Wikipedia article. Some subsequent mentions are also
linked, when it suits the surrounding text.
parent f4471fc728d372861095d8f0a5b19831e316ead7
author Sandip Mane <sandip.mane@bigbinary.com> 1593247595 +0530
committer Sandip Mane <sandip2490@gmail.com> 1597253412 +0530
Adds doc for habtm association for always optional: true
Added docs line under definition of habtm with a text containing habtm refers to zero or more associations
Added docs line under definition of habtm with a text containing it refers to zero or more associations
Updated the sentence to include declaring association for habtm relation
The original text indicated that 3 examples were forthcoming, yet alas only on `Car` model was created. No `Bike` nor `Bus`. I've reworded the text so that the reader is not left in suspense for the missing examples.
Using words such as 'just', 'simply' and 'easy' implies to the reader
that the tasks they are trying to accomplish are tasks that anyone can
do, which might then frustrate them if they find it difficult to
complete.
This commit rephrases some usage of these words to aid understanding in
the readers without making them feel belittled.
[ci skip]
This PR addresses the issue described in #28025. On `dependent: :nullify` strategy only the foreign key of the relation is nullified. However on polymorphic associations the `*_type` column is not nullified leaving the record with a NULL `*_id` but the `*_type` column is present.
I was puzzled about why `collection=` was destroying the removed
records on an association with `dependent: :destroy`, even after
consulting the documentation for that option. I had to dive into the
Active Record source to understand what was going on: eventually
`collection=` calls `collection.delete` on the ousted records, and it
also uses the `:dependent` option to decide how to remove records.
It would have helped me to have mention of this in the documentation for
`:dependent`, not just under `collection.delete` (which I found much
later).
Briefly mention the broader impacts of `:dependent` in the Association
Basics guide.
[ci skip]
This commit removes the dependent: :destroy option from the belong_to example since there is a warning associated with the usage of dependent: :destroy along with belongs_to. Based on the feedback on the issue #33914, I replaced dependent: :destroy with touch: :books_updated_at which will make the example consistent with the example that already exists on that page.
* Also Removing the touch option from the belong_to scopes example as the option doesnt have any relation to association scope.