ruby-on-rails - learn - rails help



O que o inverso faz? O que o SQL gera? (6)

Estou tentando colocar minha cabeça ao redor do inverse_of e não entendo.

Como é o sql gerado, se houver?

A opção inverse_of exibe o mesmo comportamento se usada com :has_many :belongs_to e :has_many_and_belongs_to ?

Desculpe se esta é uma questão tão básica.

Eu vi este exemplo:

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

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

https://src-bin.com


Answer #1

Apenas uma atualização para todos - nós apenas usamos o inverse_of com um dos nossos apps com um has_many :through associação

Basicamente, ele disponibiliza o objeto "origem" para o objeto "filho"

Então, se você estiver usando o exemplo do 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

Usando :inverse_of permitirá que você acesse o objeto de dados que é o inverso de, sem realizar mais consultas SQL



Answer #3

Da documentação do Rails 5.0 e ótimo.

Guide

Associações Bidirecionais

É normal que as associações trabalhem em duas direções, exigindo declaração em dois modelos diferentes:

class Author < ApplicationRecord
  has_many :books
end

class Book < ApplicationRecord
  belongs_to :author
end

Por padrão, o Active Record não sabe sobre a conexão entre essas associações. Isso pode levar a duas cópias de um objeto ficando fora de sincronia:

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

Isso acontece porque a e b.author são duas representações diferentes na memória dos mesmos dados, e nenhuma delas é atualizada automaticamente das alterações para a outra. O Active Record fornece a opção: inverse_of para que você possa informar sobre essas relações:

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

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

Com essas alterações, o Active Record carregará apenas uma cópia do objeto do autor, evitando inconsistências e tornando o aplicativo mais eficiente:

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

Existem algumas limitações para o suporte inverse_of:

Eles não trabalham com: através de associações. Eles não trabalham com: associações polimórficas. Eles não trabalham com: como associações.

Para associações belongs_to, as associações inversas has_many são ignoradas. Cada associação tentará encontrar automaticamente a associação inversa e definir a opção: inverse_of heuristicamente (com base no nome da associação). A maioria das associações com nomes padrão será suportada. No entanto, as associações que contêm as seguintes opções não terão suas inversas definidas automaticamente:

  • condições
  • :através
  • : polimórfico
  • : foreign_key

Answer #4

Eu acho que :inverse_of é mais útil quando você está trabalhando com associações que ainda não foram persistidas. Por exemplo:

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

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

Agora, no console:

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

Sem os argumentos :inverse_of , t.project retornaria nil , porque dispara uma consulta sql e os dados não são armazenados ainda. Com os argumentos :inverse_of , os dados são recuperados da memória.


Answer #5

Quando temos 2 modelos com relacionamento has_many e belongs_to, é sempre melhor usar o inverso_do qual informa ao ActiveRecod que eles pertencem ao mesmo lado da associação. Portanto, se uma consulta de um lado for acionada, ela será armazenada em cache e servida no cache se for acionada na direção oposta. Qual melhora no desempenho. Do Rails 4.1, inverse_of será definido automaticamente, se usar foreign_key ou alterações no nome da classe, precisamos definir explicitamente.

Melhor artigo para detalhes e exemplo.

blog


Answer #6

Se você tem uma relação has_many_through entre dois modelos, User e Role, e deseja validar o modelo de conexão Assignment contra entradas não existentes ou inválidas com validates_presence of :user_id, :role_id , é útil. Você ainda pode gerar um User @user com sua associação @user.role(params[:role_id]) para que salvar o usuário não resulte em uma validação com falha do modelo de atribuição.