reverse_ofは何をしますか?どのSQLを生成しますか?


143

私は頭を動かそうとしていますが、inverse_ofうまくいきません。

生成されたSQLはどのように見えますか?

ないinverse_ofで使用する場合のオプションは同じ挙動を示す:has_many:belongs_to:has_many_and_belongs_to

これがそのような基本的な質問であれば申し訳ありません。

私はこの例を見ました:

class Player < ActiveRecord::Base
  has_many :cards, :inverse_of => :player
end

class Card < ActiveRecord::Base
  belongs_to :player, :inverse_of => :cards
end

回答:


125

以下からのドキュメントのように、それはそうです:inverse_ofオプションは、それらを生成しない、SQLクエリを回避するための方法です。関係を介して再度フェッチするのではなく、すでにロードされているデータを使用することはActiveRecordへのヒントです。

彼らの例:

class Dungeon < ActiveRecord::Base
  has_many :traps, :inverse_of => :dungeon
  has_one :evil_wizard, :inverse_of => :dungeon
end

class Trap < ActiveRecord::Base
  belongs_to :dungeon, :inverse_of => :traps
end

class EvilWizard < ActiveRecord::Base
  belongs_to :dungeon, :inverse_of => :evil_wizard
end

この場合、呼び出しでdungeon.traps.first.dungeondungeon、デフォルトの場合のように新しいオブジェクトをロードするのではなく、元のオブジェクトを返す必要があります。


5
ドキュメントのコメントを理解していますか:「belongs_toアソシエーションの場合、has_many逆アソシエーションは無視されます。」それでも、ドキュメントはその正確な例を使用しています。ここで何が欠けていますか?
dynex 2012

50
デフォルトでは常にこの動作が必要であり、関連付け名を推測できない場合にのみ:inverse_ofを使用する必要があるように思えるため、これはすべて私にとって非常に奇妙です。また、定義の不一致は厄介ですが、いくつかのケースで助けになりました。どこにでも貼り付けてはいけない理由は?
イブラヒム

18
@Ibrahimこれをチェックしてください。23日前にマージされました。github.com/rails/rails/pull/9522
Hut8、

6
レコードAの親レコードの子がレコードAであることが保証されていないため、belongs_toアソシエーションの逆が無視されるのは理にかなっています。レコードAの兄弟である可能性があります。ただし、レコードAの子の親は、レコードA.あることが保証されている
デヴィッド・オルドリッジ

2
将来の読者はこのブログから助けを得るかもしれません...:D
Arup Rakshit 2015

42

:inverse_ofまだ永続化されていない関連付けを使用している場合に最も役立つと思います。例えば:

class Project < ActiveRecord::Base
  has_many :tasks, :inverse_of=>:project
end

class Task < ActiveRecord::Base
  belongs_to :project, :inverse_of=>:tasks
end

次に、コンソールで:

irb> p = Project.new
=> #<Project id: nil, name: nil, ...>
irb> t = p.tasks.build
=> #<Task id: nil, project_id: nil, ...>
irb> t.project
=> #<Project id: nil, name: nil, ...>

:inverse_of引数がない場合、t.projectnilSQLクエリをトリガーし、データはまだ保存されていないため、を返します。では:inverse_of、引数、データがメモリから取り出されます。


1
accepts_nested_attributes_forに問題がありました。デフォルトでは、既存の関連オブジェクトのネストされた属性のみが表示されます(編集アクション)。たとえば、3つの関連オブジェクトを持つオブジェクトを作成する場合は、モデルにModel.new(新しいアクション)と:inverse_ofが必要です。
Victor Marconi、

Rails 4以降での動作については同意しましたが、v3では問題なく動作しました(古い構文はv3.2.13でも再び機能しますが、後の一部の実装を除きます)。また、join-modelでは、idの存在を検証できないことに注意してください。モデルオブジェクトのみです。v4 'logic'では、IDなしの関連付けができるようです。
JosephK

正確に.. :inverse_of同じフォームで新しい親エンティティと子エンティティを作成するときの問題を解決しました。
WM

16

このpr(https://github.com/rails/rails/pull/9522)の後、ほとんどの場合、inverse_ofは必要ありません。

Active Recordは、標準名とのほとんどの関連付けの自動識別をサポートしています。ただし、アクティブレコードは、スコープまたは次のオプションのいずれかを含む双方向の関連付けを自動的に識別しません。

  • :使って
  • :外部キー
class Author < ApplicationRecord
  has_many :books, inverse_of: 'writer'
end

class Book < ApplicationRecord
  belongs_to :writer, class_name: 'Author', foreign_key: 'author_id'
end

a = Author.first
b = a.books.first
a.first_name == b.writer.first_name # => true
a.first_name = 'David'
a.first_name == b.writer.first_name # => true

上記の例では、同じオブジェクトへの参照が変数aと属性に格納されていますwriter


私はRails 5を使用しています。追加するinverse_ofかしないかにかかわらず、結果a.first_name == b.author.first_nameは常にtureです。
Arslan Ali、

@ArslanAli素晴らしいコメントをありがとう、私は答えを更新しました。
artamonovdev

5

皆のための単なるアップデート- inverse_of私たちはhas_many :through関連付けのあるアプリの1つで使用しました


基本的には、「origin」オブジェクトを「child」オブジェクトで使用できるようにします

したがって、Railsの例を使用している場合:

class Dungeon < ActiveRecord::Base
  has_many :traps, :inverse_of => :dungeon
  has_one :evil_wizard, :inverse_of => :dungeon
end

class Trap < ActiveRecord::Base
  belongs_to :dungeon, :inverse_of => :traps
  validates :id,
      :presence => { :message => "Dungeon ID Required", :unless => :draft? }

  private
  def draft?
      self.dungeon.draft
  end 
end

class EvilWizard < ActiveRecord::Base
  belongs_to :dungeon, :inverse_of => :evil_wizard
end

を使用:inverse_ofすると、それ以上のSQLクエリを実行せずに、その逆であるデータオブジェクトにアクセスできます。


5

has_manyとbelongs_toの関係を持つ2つのモデルがある場合、常にActiveRecodに関連の同じ側に属していることを知らせる、inverse_ofを使用する方が良いでしょう。そのため、片側からのクエリがトリガーされた場合、反対方向からトリガーされた場合、キャッシュされ、キャッシュから提供されます。パフォーマンスが向上します。Rails 4.1以降では、inverse_ofが自動的に設定されます。foreign_keyを使用する場合、またはクラス名を変更する場合は、明示的に設定する必要があります。

詳細と例のための最高の記事。

http://viget.com/extend/exploring-the-inverse-of-option-on-rails-model-associations



3

あなたが持っている場合はhas_many_through2機種、ユーザーおよびロールの間の関係を、そして持つ非存在または無効なエントリに対する接続モデルの割り当てを検証するvalidates_presence of :user_id, :role_id、それが便利です。ユーザー@user.role(params[:role_id])を保存しても割り当てモデルの検証に失敗しないように、ユーザー@ユーザーとその関連付けを引き続き生成できます。


-1

2つの役立つリソースを見てください。

そして、いくつかの制限を覚えておいてくださいinverse_of

:throughアソシエーションでは機能しません。

:polymorphicアソシエーションでは機能しません。

belongs_toアソシエーションの場合、has_many逆アソシエーションは無視されます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.