2012-02-15 53 views
109

Tôi đang cố gắng để có được đầu của tôi xung quanh inverse_of và tôi không nhận được nó.Inverse_of làm gì? SQL nó tạo ra cái gì?

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

Tùy chọn inverse_of có thể thực hiện hành vi tương tự nếu được sử dụng với :has_many, :belongs_to:has_many_and_belongs_to?

Xin lỗi nếu đây là câu hỏi cơ bản như vậy.

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 

Trả lời

98

Từ the documentation, nó có vẻ như tùy chọn :inverse_of 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 ý để ActiveRecord sử dụng dữ liệu đã tải thay vì tìm nạp lại thông qua một mối quan hệ.

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, gọi dungeon.traps.first.dungeon nên trả lại đối tượng gốc dungeon thay vì tải một cái mới như sẽ là trường hợp theo mặc định.

+5

Bạn có hiểu nhận xét trong tài liệu: "đối với các liên kết thuộc đối tượng has_many các liên kết nghịch đảo bị bỏ qua". Tuy nhiên, doc sử dụng ví dụ chính xác đó. Tôi đang thiếu gì ở đây? – dynex

+1

Tôi không hoàn toàn chắc chắn. 'inverse_of' đã không thực sự nhìn thấy rất nhiều sử dụng vì vậy nó có thể là một hành vi đó không phải là rất tốt được xác định. Tôi đã thử sử dụng nó sau khi bạn chỉ ra rằng tính năng và nó đã không thực sự làm bất cứ điều gì hữu ích cho tôi. – tadman

+46

Điều này rất lạ đối với tôi, bở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 không thể suy ra tên hiệp hội. Ngoài ra những mâu thuẫ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 kỳ lý do gì tôi không nên chỉ dính nó ở khắp mọi nơi? – Ibrahim

3

Nếu bạn có mối quan hệ has_many_through 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 Chuyển nhượng với các mục nhập không tồn tại hoặc không hợp lệ với validates_presence of :user_id, :role_id, thì sẽ hữu ích. Bạn vẫn có thể tạo User @user với liên kết của mình @user.role(params[:role_id]) để lưu người dùng sẽ không dẫn đến việc xác thực không thành công của mô hình Nhiệm vụ.

5

Chỉ cần 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_of với một trong những ứng dụng của chúng tôi với một hiệp hội has_many :through


Về cơ bản nó làm cho "nguồn gốc" đối tượng có sẵn cho các đối tượng "trẻ em"

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 

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

30

Tôi nghĩ :inverse_of là hữu ích nhất khi bạn đang làm việc với các hiệp hội mà 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 giao diện đ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ó sự: inverse_of lập luận, t.project sẽ trở về con số không, bởi vì nó gây ra một truy vấn sql và các dữ liệu không được lưu trữ được nêu ra. Với các đối số inverse_of, dữ liệu được lấy ra từ bộ nhớ.

+0

Tôi gặp sự cố với accepts_nested_attributes_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ó (chỉnh sửa hành động). Nếu, ví dụ, bạn muốn TẠO một đối tượng với 3 đối tượng 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. –

+0

Đồng ý về hành vi trong Rails 4 và sau đó, nhưng nó 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 kết nối, không thể xác thực sự hiện diện của id nữa - chỉ có đối tượng mô hình. Dường như bạn có thể có một hiệp hội mà không có một id cho nó, trong v4 'logic'. – JosephK

+0

Chính xác .. ': inverse_of' giải quyết vấn đề cho tôi khi tạo các thực thể cha và con mới trong cùng một biểu mẫu. –

4

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

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

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

7

Từ tài liệu về Rails 5.0 và tuyệt vời.

Guide

Bi-directional Hội

Đó là bình thường đối với các hiệp hội để làm việc theo hai hướng, đòi hỏi phải khai trên hai mô hình khác nhau:

class Author < ApplicationRecord 
    has_many :books 
end 

class Book < ApplicationRecord 
    belongs_to :author 
end 

Theo mặc định, Active Record doesn' t biết về kết nối giữa các liên kết này. Điều này có thể dẫn đến hai bản sao của một đối tượng nhận ra đồng bộ:

a = Author.first 
b = a.books.first 
a.first_name == b.author.first_name # => true 
a.first_name = 'Manny' 
a.first_name == b.author.first_name # => false 

Điều này xảy ra bởi vì a và b.author hai cơ quan đại diện khác nhau trong bộ nhớ của cùng một dữ liệu, và không ai được tự động làm mới từ những thay đổi để cai khac. Active Record cung cấp: Tùy chọn inverse_of để bạn có thể thông báo cho nó những quan hệ:

class Author < ApplicationRecord 
    has_many :books, inverse_of: :author 
end 

class Book < ApplicationRecord 
    belongs_to :author, inverse_of: :books 
end 

Với những thay đổi này, Active Record sẽ chỉ tải một bản sao của đối tượng tác giả, ngăn chặn mâu thuẫn và làm cho ứng dụng của bạn hiệu quả hơn:

a = Author.first 
b = a.books.first 
a.first_name == b.author.first_name # => true 
a.first_name = 'Manny' 
a.first_name == b.author.first_name # => true 

có một vài hạn chế đối với inverse_of hỗ trợ:

Họ không làm việc với: thông qua các hiệp hội. Chúng không hoạt động với: các hiệp hội đa hình. Chúng không hoạt động với: như các liên kết.

Đối với các liên kết thuộc đối tượng, các liên kết nghịch đảo has_many bị bỏ qua. Mọi liên kết sẽ tìm cách tự động tìm liên kết nghịch đảo và đặt tùy chọn: inverse_of theo phương pháp heuristically (dựa trên tên liên kết). Hầu hết các liên kết có tên chuẩn sẽ được hỗ trợ.Tuy nhiên, các hiệp hội có chứa các tùy chọn sau đây sẽ không có phần tử nghịch đảo của họ thiết lập tự động:

  • : Điều kiện
  • : thông qua
  • : đa hình
  • : foreign_key
+0

Tôi đang sử dụng Rails 5 và bạn có thể thêm 'inverse_of' hoặc không, kết quả cho' a.first_name == b.author.first_name' luôn là ture. –

-1

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

Và hãy 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: các liên kết đa hình.

cho các liên kết thuộc đối tượng has_many các liên kết nghịch đảo bị bỏ qua.

Các vấn đề liên quan