Что делает inverse_of? Какой SQL он генерирует? - PullRequest
128 голосов
/ 15 февраля 2012

Я пытаюсь обернуться 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

Ответы [ 8 ]

113 голосов
/ 15 февраля 2012

Из документации кажется, что опция :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.dungeon должен вернуть исходный объект dungeon вместо загрузки нового, как это было бы по умолчанию.

38 голосов
/ 07 марта 2014

Я думаю, :inverse_of наиболее полезен, когда вы работаете с ассоциациями, которые еще не были сохранены. E.g.:

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.project вернет nil, потому что запускает SQL-запрос и данные еще не сохранены. С аргументами :inverse_of данные извлекаются из памяти.

13 голосов
/ 24 сентября 2016

Из документации Rails 5.0 и выше.

Guide

Двунаправленные ассоциации

Это нормально для ассоциацийработать в двух направлениях, требуя декларирования для двух разных моделей:

class Author < ApplicationRecord
  has_many :books
end

class Book < ApplicationRecord
  belongs_to :author
end

По умолчанию Active Record не знает о связи между этими ассоциациями.Это может привести к потере синхронизации двух копий объекта:

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

Это происходит потому, что a и b.author - это два разных представления в памяти одних и тех же данных, и ни одно из них автоматически не обновляется изменяется на другой.Active Record предоставляет опцию: inverse_of, чтобы вы могли сообщить ей об этих отношениях:

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

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

С этими изменениями Active Record загрузит только одну копию объекта автора, предотвращая несоответствия и делая ваше приложение более эффективным:

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

Существует несколько ограничений поддержки inverse_of:

Они не работают с: через ассоциации.Они не работают с: полиморфными ассоциациями.Они не работают с: как с ассоциациями.

Для ассоциаций принадлежат_, обратные ассоциации has_many игнорируются.Каждая ассоциация будет пытаться автоматически найти обратную ассоциацию и установить эвристическую опцию: inverse_of (на основе имени ассоциации).Большинство ассоциаций со стандартными именами будут поддерживаться.Однако для ассоциаций, содержащих следующие параметры, обратные установки не будут установлены автоматически:

  • : условия
  • : до
  • : полиморфное
  • :Foreign_key
5 голосов
/ 29 ноября 2013

Просто обновление для всех - мы только что использовали inverse_of с одним из наших приложений с has_many :through ассоциацией


Это в основном делает объект "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

4 голосов
/ 09 мая 2015

Когда у нас есть 2 модели с отношениями has_many и own_to, всегда лучше использовать inverse_of, который сообщает ActiveRecod, что они принадлежат одной и той же стороне ассоциации. Таким образом, если запрос с одной стороны запущен, он будет кэшироваться и обслуживаться из кэша, если он будет запущен с противоположного направления. Что улучшает производительность. Начиная с Rails 4.1, inverse_of будет устанавливаться автоматически, если мы используем foreign_key или изменения в имени класса, которые мы должны установить явно.

Лучшая статья для деталей и примера.

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

3 голосов
/ 18 июля 2013

Взгляните на эту статью !!

http://gsusmonzon.blogspot.com.br/2011/09/rails-power-of-inverseof.html

3 голосов
/ 23 февраля 2013

Если у вас есть отношение has_many_through между двумя моделями, пользователем и ролью, и вы хотите проверить присвоение соединительной модели по несуществующим или недействительным записям с помощью validates_presence of :user_id, :role_id, это полезно. Вы все еще можете сгенерировать User @user с его ассоциацией @user.role(params[:role_id]), чтобы сохранение пользователя не привело к неудачной проверке модели Assignment.

0 голосов
/ 25 октября 2016

Пожалуйста, взгляните на 2 двух полезных ресурса

И помните некоторые ограничения inverse_of:

не работает с: посредством ассоциаций.

не работает с: полиморфными ассоциациями.

для ассоциаций принадлежащих_символов обратные ассоциации has_many игнорируются.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...