Inverse_of làm gì? SQL tạo ra cái gì?


143

Tôi đang cố gắng để có được đầu của tôi xung quanh inverse_ofvà tôi không nhận được nó.

Sql được tạo ra trông như thế nào, nếu có?

Liệu inverse_oflựa chọn triển lãm các hành vi tương tự nếu sử dụng với :has_many, :belongs_to:has_many_and_belongs_to?

Xin lỗi nếu đây là một câu hỏi cơ bản.

Tôi đã thấy ví dụ này:

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

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

Câu trả lời:


125

Từ tài liệu này , có vẻ như :inverse_oftùy chọn là một phương pháp để tránh các truy vấn SQL, không tạo ra chúng. Đó là một gợi ý cho ActiveRecord để sử dụng dữ liệu đã được tải thay vì tìm nạp lại thông qua mối quan hệ.

Ví dụ của họ:

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

Trong trường hợp này, việc gọi dungeon.traps.first.dungeonsẽ trả về dungeonđối tượng ban đầu thay vì tải một đối tượng mới như trường hợp mặc định.


5
Bạn có hiểu nhận xét trong tài liệu: "cho các hiệp hội thuộc về các liên kết has_many bị bỏ qua." Nhưng tài liệu sử dụng ví dụ chính xác đó. Tôi đang thiếu gì ở đây?
dynex

50
Điều này rất lạ đối với tôi, vì dường như với tôi rằng bạn sẽ luôn muốn hành vi này theo mặc định và chỉ cần sử dụng: inverse_of khi tên hiệp hội không thể được suy ra. Ngoài ra sự không nhất quán trong định nghĩa là khó chịu, nhưng nó đã giúp tôi trong một vài trường hợp. Bất cứ lý do nào tôi không nên chỉ dán nó ở khắp mọi nơi?
Ibrahim

18
@Ibrahim Hãy xem cái này, nó đã được hợp nhất 23 ngày trước! github.com/rails/rails/pull/9522
Hut8

6
Điều này hợp lý khi nghịch đảo của một liên kết thuộc về bị bỏ qua vì con của bản ghi A hồ sơ cha mẹ A không được bảo đảm là bản ghi A - tuy nhiên, đó có thể là anh chị em của Bản ghi A. Tuy nhiên, cha mẹ của một đứa trẻ của bản ghi A , được đảm bảo là kỷ lục A.
David Aldridge

2
Độc giả tương lai có thể nhận trợ giúp từ blog này ...: D
Arup Rakshit

42

Tôi nghĩ :inverse_oflà hữu ích nhất khi bạn đang làm việc với các hiệp hội chưa được kiên trì. Ví dụ:

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

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

Bây giờ, trong bảng điều khiển:

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

Nếu không có :inverse_ofđối số, t.projectsẽ trả về nil, vì nó kích hoạt truy vấn sql và dữ liệu chưa được lưu trữ. Với các :inverse_ofđối số, dữ liệu được lấy từ bộ nhớ.


1
Tôi đã gặp sự cố với ac accept_nested_attribut_for. Theo mặc định, chỉ các thuộc tính lồng nhau cho các đối tượng liên quan hiện có hiển thị (chỉnh sửa hành động). Ví dụ: nếu bạn muốn TẠO một đối tượng với 3 đối tượng được liên kết, bạn nên có Model.new (hành động mới) và: inverse_of trong các mô hình của bạn.
Victor Marconi

Đồng ý với hành vi trong Rails 4 trở lên, nhưng nó chỉ hoạt động tốt trong v3 (ngoại trừ một số hóa thân sau này, mặc dù cú pháp cũ hoạt động trở lại trong v3.2.13). Và lưu ý trong mô hình tham gia, không thể xác thực sự hiện diện của id nữa - chỉ đối tượng mô hình. Có vẻ như bạn có thể có một liên kết mà không có id cho nó, trong v4 'logic'.
JosephK

Chính xác .. đã :inverse_ofgiải quyết một vấn đề cho tôi khi tạo các thực thể cha mẹ và con mới trong cùng một hình thức.
WM

16

Sau pr này ( https://github.com/rails/rails/pull/9522 ) inverse_of không bắt buộc trong hầu hết các trường hợp.

Active Record hỗ trợ nhận dạng tự động cho hầu hết các hiệp hội với tên tiêu chuẩn. Tuy nhiên, Bản ghi hoạt động sẽ không tự động xác định các liên kết hai chiều có chứa phạm vi hoặc bất kỳ tùy chọn nào sau đây:

  • :xuyên qua
  • : nước ngoài
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

Trong ví dụ trên, một tham chiếu đến cùng một đối tượng được lưu trữ trong biến avà trong thuộc tính writer.


Tôi đang sử dụng Rails 5, và bạn có thêm inverse_ofhay không, kết quả cho a.first_name == b.author.first_nameluôn luôn là chắc chắn.
Arslan Ali

@ArslanAli cảm ơn vì nhận xét tuyệt vời, tôi đã cập nhật câu trả lời.
artamonovdev

5

Chỉ là một bản cập nhật cho tất cả mọi người - chúng tôi chỉ sử dụng inverse_ofvới một trong các ứng dụng của mình với một has_many :throughhiệp hội


Về cơ bản, nó làm cho đối tượng "gốc" có sẵn cho đối tượng "con"

Vì vậy, nếu bạn đang sử dụng ví dụ của 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

Việc sử dụng :inverse_ofsẽ cho phép bạn truy cập vào đối tượng dữ liệu mà nó nghịch đảo, mà không thực hiện bất kỳ truy vấn SQL nào nữa


5

Khi chúng tôi có 2 mô hình có mối quan hệ has_many và thuộc về mối quan hệ, việc sử dụng inverse_of sẽ thông báo cho ActiveRecod rằng chúng thuộc cùng một phía của hiệp hội. Vì vậy, nếu một truy vấn từ một phía được kích hoạt, nó sẽ lưu trữ và phục vụ từ bộ đệm nếu nó được kích hoạt từ hướng ngược lại. Mà cải thiện hiệu suất. Từ Rails 4.1, inverse_of sẽ được đặt tự động, nếu chúng tôi sử dụng Foreign_key hoặc thay đổi tên lớp, chúng tôi cần đặt rõ ràng.

Bài viết tốt nhất để biết chi tiết và ví dụ.

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



3

Nếu bạn có has_many_throughmối quan hệ giữa hai mô hình, Người dùng và Vai trò và muốn xác thực Mô hình kết nối Bài tập đối với các mục không tồn tại hoặc không hợp lệ với validates_presence of :user_id, :role_id, điều đó rất hữu ích. Bạn vẫn có thể tạo Người dùng @user với liên kết của mình @user.role(params[:role_id])để việc lưu người dùng sẽ không dẫn đến việc xác thực mô hình Chuyển nhượng không thành công.


-1

Xin hãy xem 2 hai tài nguyên hữu ích

Và nhớ một số hạn chế của inverse_of:

không làm việc với: thông qua các hiệp hội.

không hoạt động với: hiệp hội đa hình.

đối với các hiệp hội thuộc về has_many, các hiệp hội nghịch đảo bị bỏ qua.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.