Apa yang dilakukan inverse_of? Apa SQL yang dihasilkannya?

143

Saya mencoba untuk mendapatkan kepalaku inverse_ofdan saya tidak mengerti.

Seperti apa bentuk sql yang dihasilkan, jika ada?

Apakah inverse_ofpilihan menunjukkan perilaku yang sama jika digunakan dengan :has_many, :belongs_to, dan :has_many_and_belongs_to?

Maaf jika ini pertanyaan mendasar.

Saya melihat contoh ini:

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

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

Jawaban:

125

Dari dokumentasi , sepertinya :inverse_ofopsi adalah metode untuk menghindari permintaan SQL, bukan menghasilkan mereka. Ini adalah petunjuk bagi ActiveRecord untuk menggunakan data yang sudah dimuat alih-alih mengambilnya lagi melalui suatu hubungan.

Contoh mereka:

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

Dalam hal ini, panggilan dungeon.traps.first.dungeonharus mengembalikan dungeonobjek asli alih-alih memuat yang baru seperti halnya secara default.

anak laki-laki
sumber
5
Apakah Anda memahami komentar dalam dokumentasi: "untuk asosiasi milik_to, banyak asosiasi terbalik diabaikan.". Namun dokter menggunakan contoh yang tepat. Apa yang kulewatkan di sini?
dynex
50
Ini semua sangat aneh bagi saya, karena bagi saya sepertinya Anda selalu menginginkan perilaku ini secara default, dan hanya perlu menggunakan: inverse_of ketika nama asosiasi tidak dapat disimpulkan. Juga ketidakkonsistenan dalam definisi itu menyusahkan, tetapi itu membantu saya dalam beberapa kasus. Adakah alasan saya tidak seharusnya menempel di mana-mana?
Ibrahim
18
@Ibrahim Lihat ini, sudah bergabung 23 hari yang lalu! github.com/rails/rails/pull/9522
Hut8
6
Masuk akal jika kebalikan dari asosiasi hers_to diabaikan karena anak dari catatan orang tua A tidak dijamin menjadi catatan A - itu bisa merupakan saudara kandung dari Catatan A. Orang tua dari anak dari catatan A, namun , dijamin sebagai rekor A.
David Aldridge
2
Pembaca masa depan mungkin mendapatkan bantuan dari blog ini ...: D
Arup Rakshit
42

Saya pikir :inverse_ofini sangat berguna ketika Anda bekerja dengan asosiasi yang belum ada. Misalnya:

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

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

Sekarang, di konsol:

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, ...>

Tanpa :inverse_ofargumen, t.projectakan kembali nil, karena memicu kueri sql dan data belum disimpan. Dengan :inverse_ofargumen, data diambil dari memori.

KenB
sumber
1
Saya punya masalah dengan accepts_nested_attributes_for. Secara default, hanya atribut bersarang untuk objek terkait yang ada menunjukkan (edit tindakan). Jika, misalnya, Anda ingin MENCIPTAKAN objek dengan, katakanlah, 3 objek terkait, Anda harus memiliki Model.new (aksi baru) dan: inverse_of dalam model Anda.
Victor Marconi
Menyetujui perilaku dalam Rails 4 dan yang lebih baru, tetapi itu bekerja dengan baik di v3 (kecuali beberapa inkarnasi kemudian, meskipun sintaks lama bekerja lagi di v3.2.13). Dan perhatikan dalam model gabungan, tidak dapat memvalidasi keberadaan id lagi - hanya objek model. Tampaknya Anda dapat memiliki asosiasi tanpa id untuk itu, dalam 'logika' v4.
JosephK
Persis .. :inverse_ofmemecahkan masalah bagi saya saat membuat entitas induk dan anak baru dalam bentuk yang sama.
WM
16

Setelah pr ini ( https://github.com/rails/rails/pull/9522 ) inverse_of tidak diperlukan dalam kebanyakan kasus.

Rekaman Aktif mendukung identifikasi otomatis untuk sebagian besar asosiasi dengan nama standar. Namun, Rekaman Aktif tidak akan secara otomatis mengidentifikasi asosiasi dua arah yang berisi lingkup atau salah satu dari opsi berikut:

  • :melalui
  • :kunci asing
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

Dalam contoh di atas, referensi ke objek yang sama disimpan dalam variabel adan atribut writer.

artamonovdev
sumber
Saya menggunakan Rails 5, dan apakah Anda menambahkan inverse_ofatau tidak, hasilnya a.first_name == b.author.first_nameadalah selalu mendatang.
Arslan Ali
@ArslanAli terima kasih atas komentarnya, saya memperbarui jawabannya.
artamonovdev
5

Hanya pembaruan untuk semua orang - kami baru saja menggunakan inverse_ofsalah satu aplikasi kami dengan sebuah has_many :throughasosiasi


Ini pada dasarnya membuat objek "asal" tersedia untuk objek "anak"

Jadi jika Anda menggunakan contoh 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

Menggunakan :inverse_ofakan memungkinkan Anda untuk mengakses objek data yang kebalikannya, tanpa melakukan query SQL lebih lanjut

Richard Peck
sumber
5

Ketika kami memiliki 2 model dengan hubungan has_many dan hers_to, selalu lebih baik menggunakan inverse_of yang memberi tahu ActiveRecod bahwa mereka memiliki sisi yang sama dengan asosiasi. Jadi, jika kueri dari satu sisi dipicu, ia akan melakukan cache dan melayani dari cache jika itu dipicu dari arah yang berlawanan. Yang meningkatkan kinerja. Dari Rails 4.1, inverse_of akan diatur secara otomatis, jika kita menggunakan foreign_key atau perubahan nama kelas, kita perlu mengatur secara eksplisit.

Artikel terbaik untuk detail dan contoh.

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

Gurudath BN
sumber
3

Jika Anda memiliki has_many_throughhubungan antara dua model, Pengguna dan Peran, dan ingin memvalidasi Penugasan model penghubung dengan entri yang tidak ada atau tidak valid dengan validates_presence of :user_id, :role_id, itu berguna. Anda masih dapat menghasilkan Pengguna @ pengguna dengan asosiasinya @user.role(params[:role_id])sehingga menyimpan pengguna tidak akan menghasilkan validasi gagal model Penugasan.

Informatom
sumber
-1

Silakan lihat 2 dua sumber daya yang berguna

Dan ingat beberapa batasan inverse_of:

tidak bekerja dengan: melalui asosiasi.

tidak bekerja dengan: asosiasi polimorfik.

untuk asosiasi Hers_to, asosiasi has_many terbalik.

Leo Le
sumber