ruby-on-rails active - ¿Qué hace reverse_of do? ¿Qué SQL genera?





record console (8)


Si tiene una relación has_many_through entre dos modelos, Usuario y Función, y desea validar la Asignación del modelo de conexión con entradas no válidas o no válidas con validates_presence of :user_id, :role_id , es útil. Aún puede generar un User @user con su asociación @user.role(params[:role_id]) para que guardar al usuario no @user.role(params[:role_id]) resultado una validación fallida del modelo de Asignación.

inverse_of girar la cabeza de manera inverse_of y no lo entiendo.

¿Cómo se ve el sql generado, si hay alguno?

¿ inverse_of opción inverse_of exhibe el mismo comportamiento si se usa con :has_many :belongs_to , y :has_many_and_belongs_to ?

Lo siento si esta es una pregunta tan básica.

Vi este ejemplo:

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

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



Cuando tenemos 2 modelos con relaciones has_many y belongs_to, siempre es mejor usar reverse_of que informen a ActiveRecod que pertenecen al mismo lado de la asociación. Por lo tanto, si se activa una consulta desde un lado, se almacenará en caché y servirá desde el caché si se activa desde la dirección opuesta. Lo cual mejora en el rendimiento. Desde Rails 4.1, inverse_of se configurará automáticamente, si utilizamos foreign_key o cambiamos el nombre de clase, debemos establecerlo explícitamente.

Mejor artículo para detalles y ejemplo.

blog




Por favor, eche un vistazo a 2 dos recursos útiles

Y recuerda algunas limitaciones de inverse_of :

no funciona con: a través de asociaciones.

no funciona con: asociaciones polimórficas.

para las asociaciones belongs_to has_many se ignoran las asociaciones inversas.




De la documentación , parece que la opción :inverse_of es un método para evitar consultas SQL, no generarlas. Es una sugerencia para que ActiveRecord use datos ya cargados en lugar de recuperarlos nuevamente a través de una relación.

Su ejemplo:

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

En este caso, si llama a dungeon.traps.first.dungeon debe devolver el objeto de dungeon original en lugar de cargar uno nuevo, como sería el caso de forma predeterminada.




De la documentación de Rails 5.0 y excelente.

Guide

Asociaciones bidireccionales

Es normal que las asociaciones trabajen en dos direcciones, lo que requiere una declaración sobre dos modelos diferentes:

class Author < ApplicationRecord
  has_many :books
end

class Book < ApplicationRecord
  belongs_to :author
end

Por defecto, Active Record no sabe acerca de la conexión entre estas asociaciones. Esto puede llevar a que dos copias de un objeto no se sincronicen:

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

Esto sucede porque a y b.author son dos representaciones en memoria diferentes de los mismos datos, y ninguno se actualiza automáticamente de los cambios a la otra. Active Record proporciona la opción: inverse_of para que pueda informarle de estas relaciones:

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

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

Con estos cambios, Active Record solo cargará una copia del objeto de autor, lo que evitará inconsistencias y hará que su aplicación sea más 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

Hay algunas limitaciones para reverse_of support:

No trabajan con: a través de asociaciones. No funcionan con: asociaciones polimórficas. No trabajan con: como asociaciones.

Para las asociaciones belongs_to, las asociaciones inversas has_many se ignoran. Cada asociación intentará encontrar automáticamente la asociación inversa y establecer la opción: Inverse_of de manera heurística (en función del nombre de la asociación). La mayoría de las asociaciones con nombres estándar serán compatibles. Sin embargo, las asociaciones que contienen las siguientes opciones no tendrán sus inversos configurados automáticamente:

  • : condiciones
  • :mediante
  • :polimórfico
  • :clave externa



Solo una actualización para todos: acabamos de usar inverse_of con una de nuestras aplicaciones con has_many :through asociación

Básicamente hace que el objeto "origen" esté disponible para el objeto "niño"

Entonces, si estás usando el ejemplo de 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

El uso de :inverse_of le permitirá acceder al objeto de datos que es el inverso de, sin realizar más consultas SQL




Creo que :inverse_of es más útil cuando trabajas con asociaciones que aún no se han conservado. P.ej:

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

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

Ahora, en la consola:

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

Sin los argumentos: reverse_of, t.project devolvería nil, porque desencadena una consulta sql y los datos aún no se almacenan. Con el argumento: reverse_of, los datos se recuperan de la memoria.




Una pregunta anterior, pero el problema en Rails 4 aún permanece. Otra opción es crear / sobreescribir dinámicamente el método _type con una preocupación. Esto sería útil si su aplicación utiliza múltiples asociaciones polimórficas con STI y desea mantener la lógica en un solo lugar.

Esta preocupación atrapará todas las asociaciones polimórficas y asegurará que el registro siempre se guarde utilizando la clase base.

# models/concerns/single_table_polymorphic.rb
module SingleTablePolymorphic
  extend ActiveSupport::Concern

  included do
    self.reflect_on_all_associations.select{|a| a.options[:polymorphic]}.map(&:name).each do |name|
      define_method "#{name.to_s}_type=" do |class_name|
        super(class_name.constantize.base_class.name)
      end
    end
  end
end

Luego solo inclúyelo en tu modelo:

class Car < ActiveRecord::Base
  belongs_to :borrowable, :polymorphic => true
  include SingleTablePolymorphic
end






ruby-on-rails activerecord