ruby-on-rails - active record rails
¿Qué hace reverse_of do? ¿Qué SQL genera? (8)
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
¡¡Mira este articulo!!
http://gsusmonzon.blogspot.com.br/2011/09/rails-power-of-inverseof.html
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.
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.
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.
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
Por favor, eche un vistazo a 2 dos recursos útiles
- https://www.viget.com/articles/exploring-the-inverse-of-option-on-rails-model-associations
- http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#module-ActiveRecord::Associations::ClassMethods-label-Bi-directional+associations
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.
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.
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