through references rails joins includes has_one has_and_belongs_to_many guide ruby-on-rails model associations

ruby on rails - references - Rieles ha_one vs pertenece_a semántica



rails references (2)

Tengo un modelo que representa un elemento de Content que contiene algunas imágenes. El número de imágenes se fija, ya que estas referencias de imágenes son muy específicas del contenido. Por ejemplo, el modelo de Content refiere al modelo de Image dos veces (imagen de perfil e imagen de fondo). Estoy tratando de evitar un has_many genérico y has_one a varios has_one ''s. La estructura actual de la base de datos se ve así:

contents - id:integer - integer:profile_image_id - integer:background_image_id images - integer:id - string:filename - integer:content_id

Simplemente no puedo averiguar cómo configurar las asociaciones correctamente aquí. El modelo de Content podría contener dos referencias de belongs_to a una Image , pero eso no parece semánticamente correcto, idealmente, una imagen pertenece al contenido, o en otras palabras, el contenido tiene dos imágenes.

Esto es lo mejor que pude pensar (rompiendo la semántica):

class Content belongs_to :profile_image, :class_name => ''Image'', :foreign_key => ''profile_image_id'' belongs_to :background_image, :class_name => ''Image'', :foreign_key => ''background_image_id'' end

¿Estoy lejos, y hay una mejor manera de lograr esta asociación?


Basado en la guía de asociaciones AR , creo que deberías usar has_one . No tiene sentido que una imagen posea un Contenido ... el Contenido seguramente posee la imagen. De la guía:

La distinción se encuentra en el lugar donde coloca la clave externa (va en la tabla para la clase que declara la asociación con el que pertenece), pero también debe reflexionar sobre el significado real de los datos. La relación has_one dice que uno de algo es tuyo, es decir, que algo apunta hacia ti.

Por último, no estoy seguro de que necesites contenidos e imágenes para tener claves externas. Mientras las imágenes hagan referencia al content_id, creo que estás bien.


La respuesta simple es configurar sus asociaciones a la inversa de lo que tiene, así:

# app/models/content.rb class Content < ActiveRecord::Base has_one :profile_image, :class_name => ''Image'' has_one :background_image, :class_name => ''Image'' end # app/models/image.rb class Image < ActiveRecord::Base belongs_to :content end

No necesita las claves externas ''background_image_id'' y ''profile_image_id'' en la tabla de contenido en absoluto.

Sin embargo, hay una solución más elegante: la herencia de una sola tabla. Configúrelo ahora en caso de que desee que las imágenes de fondo y de perfil se comporten de manera ligeramente diferente en el futuro, además de que aclarará su código hoy.

Primero, agregue una columna a su tabla de imágenes llamada tipo:

# command line script/generate migration AddTypeToImages type:string rake db:migrate

Ahora configura tus modelos de esta manera:

# app/models/content.rb class Content < ActiveRecord::Base has_one :profile_image has_one :background_image end # app/models/image.rb class Image < ActiveRecord::Base belongs_to :content end # app/models/background_image.rb class BackgroundImage < Image # background image specific code here end # app/models/profile_image.rb class ProfileImage < Image # profile image specific code here end

Ahora puedes hacer todo tipo de cosas como obtener una lista de todas las imágenes de fondo:

# script/console BackgroundImage.all

Esto es más fiel al modelo de datos que está intentando crear, permite la expansión más fácil en el futuro y le ofrece algunos métodos nuevos e interesantes hoy.

ACTUALIZAR:

Desde entonces, he creado un artículo de blog llamado Herencia de una sola tabla con pruebas que incluye más detalles y cubre las pruebas.