Infer foerign_key when inverse_of is present (#47797)

* Infer `foerign_key` when `inverse_of` is present

Automatically infer `foreign_key` on `has_one` and `has_many` associations when `inverse_of` is present.

When inverse of is present, rails has all the info it needs to figure out what the foreign_key on the associated model should be.  I can't imagine this breaking anything

* Update test models to remove redundant foreign_keys

* add changelog entry

* fix changelog grammar

Co-authored-by: Rafael Mendonça França <rafael@franca.dev>
This commit is contained in:
Daniel Whitney 2023-03-30 15:22:23 -04:00 committed by GitHub
parent aa3787ca10
commit 15369fd912
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 26 additions and 8 deletions

@ -1,3 +1,19 @@
* Infer `foerign_key` when `inverse_of` is present on `has_one` and `has_many` associations.
```ruby
has_many :citations, foreign_key: "book1_id", inverse_of: :book
```
can be simplified to
```ruby
has_many :citations, inverse_of: :book
```
and the foreign_key will be read from the corresponding `belongs_to` association.
*Daniel Whitney*
* Limit max length of auto generated index names
Auto generated index names are now limited to 62 bytes, which fits within

@ -731,6 +731,8 @@ def derive_foreign_key
"#{name}_id"
elsif options[:as]
"#{options[:as]}_id"
elsif options[:inverse_of]
inverse_of.foreign_key
else
active_record.model_name.to_s.foreign_key
end

@ -4,7 +4,7 @@ class Book < ActiveRecord::Base
belongs_to :author
belongs_to :format_record, polymorphic: true
has_many :citations, foreign_key: "book1_id", inverse_of: :book
has_many :citations, inverse_of: :book
has_many :references, -> { distinct }, through: :citations, source: :reference_of
has_many :subscriptions

@ -23,7 +23,7 @@ class Comment < ActiveRecord::Base
belongs_to :first_post, foreign_key: :post_id
belongs_to :special_post_with_default_scope, foreign_key: :post_id
has_many :children, class_name: "Comment", foreign_key: :parent_id, inverse_of: :parent
has_many :children, class_name: "Comment", inverse_of: :parent
belongs_to :parent, class_name: "Comment", counter_cache: :children_count, inverse_of: :children
alias_attribute :entry, :post

@ -58,7 +58,7 @@ class Firm < Company
has_many :unsorted_clients, class_name: "Client"
has_many :unsorted_clients_with_symbol, class_name: :Client
has_many :clients_sorted_desc, -> { order "id DESC" }, class_name: "Client"
has_many :clients_of_firm, -> { order "id" }, foreign_key: "client_of", class_name: "Client", inverse_of: :firm
has_many :clients_of_firm, -> { order "id" }, class_name: "Client", inverse_of: :firm
has_many :clients_ordered_by_name, -> { order "name" }, class_name: "Client"
has_many :unvalidated_clients_of_firm, foreign_key: "client_of", class_name: "Client", validate: false
has_many :dependent_clients_of_firm, -> { order "id" }, foreign_key: "client_of", class_name: "Client", dependent: :destroy

@ -4,7 +4,7 @@ class Human < ActiveRecord::Base
self.table_name = "humans"
has_one :face, inverse_of: :human
has_one :autosave_face, class_name: "Face", autosave: true, foreign_key: :human_id, inverse_of: :autosave_human
has_one :autosave_face, class_name: "Face", autosave: true, inverse_of: :autosave_human
has_one :polymorphic_face, class_name: "Face", as: :polymorphic_human, inverse_of: :polymorphic_human
has_one :polymorphic_face_without_inverse, class_name: "Face", as: :poly_human_without_inverse
has_many :interests, inverse_of: :human

@ -98,7 +98,7 @@ class DestructivePirate < Pirate
class FamousPirate < ActiveRecord::Base
self.table_name = "pirates"
has_many :famous_ships, inverse_of: :famous_pirate, foreign_key: :pirate_id
has_many :famous_ships, inverse_of: :famous_pirate
validates_presence_of :catchphrase, on: :conference
end

@ -24,7 +24,7 @@ def cancel_save_callback_method
class ShipWithoutNestedAttributes < ActiveRecord::Base
self.table_name = "ships"
has_many :prisoners, inverse_of: :ship, foreign_key: :ship_id
has_many :prisoners, inverse_of: :ship
has_many :parts, class_name: "ShipPart", foreign_key: :ship_id
validates :name, presence: true, if: -> { true }

@ -46,7 +46,7 @@ def two
end
end
has_many :replies, dependent: :destroy, foreign_key: "parent_id", autosave: true, inverse_of: :topic
has_many :replies, dependent: :destroy, autosave: true, inverse_of: :topic
has_many :approved_replies, -> { approved }, class_name: "Reply", foreign_key: "parent_id", counter_cache: "replies_count"
has_many :open_replies, -> { open }, class_name: "Reply", foreign_key: "parent_id"

@ -1,5 +1,5 @@
# frozen_string_literal: true
class Zine < ActiveRecord::Base
has_many :interests, inverse_of: :zine, foreign_key: "zine_id"
has_many :interests, inverse_of: :zine
end