2010-01-25 15 views
17

Tengo un modelo que representa un artículo Content que contiene algunas imágenes. La cantidad de imágenes se fija ya que estas referencias de imagen son muy específicas del contenido. Por ejemplo, el modelo Content se refiere al modelo Image dos veces (imagen de perfil e imagen de fondo). Estoy tratando de evitar un genérico has_many, y atenerme a múltiples has_one. La estructura de la base de datos actual se ve así:Rails has_one vs belongs_to semántica

contents 
    - id:integer 
    - integer:profile_image_id 
    - integer:background_image_id 

images 
    - integer:id 
    - string:filename 
    - integer:content_id 

No puedo encontrar la forma de configurar las asociaciones correctamente aquí. El modelo Content podría contener dos referencias belongs_to a Image, pero eso no parece ser semánticamente correcto porque idealmente una imagen pertenece al contenido, o en otras palabras, el contenido tiene dos imágenes.

Esto es lo mejor que podía 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 

allí estoy lejos, y una mejor forma de lograr esta asociación?

Respuesta

22

La respuesta sencilla 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 

Usted 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: herencia de mesa única. Configúrelo ahora en caso de que desee que las imágenes de fondo y de perfil se comporten de forma ligeramente diferente en el futuro, además de que aclarará su código hoy.

En primer lugar, añadir una columna a sus imágenes tabla llamada Tipo:

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

Ahora configurar sus modelos de la siguiente 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 

ya se puede hacer todo tipo de cosas como conseguir una lista de todas las imágenes de fondo:

# script/console 
BackgroundImage.all 

Esto es más cierto para el modelo de datos que está tratando de crear, permite la capacidad de expansión más fácil en el futuro, y le da algunos métodos nuevos y geniales hoy.

ACTUALIZACIÓN:

Desde entonces, he creado un blog llamado artículo Single-Table Inheritance with Tests que entra en más detalles, y cubre la prueba.

+0

La herencia de una sola tabla funciona perfectamente para mi problema. ¿Sabes cómo voy a integrar las ITS con las asociaciones polimórficas? Por ejemplo, si junto con el contenido, había algunas imágenes que formaban parte de los metadatos del documento, y ambas imágenes de contenido y metadatos se almacenaban en la tabla de imágenes. – Anurag

+0

muchas gracias por el artículo. ¡tiene que ser el mejor artículo sobre la herencia de una sola tabla para Rails en la red! – Anurag

+0

Para la 'respuesta simple', ¿cómo sabría el contenido a qué imágenes hacer referencia si no hay claves externas en su tabla db? – greg7gkb

1

Basado en the AR associations guide, creo que deberías usar has_one. No tiene sentido que una imagen sea propietaria de un Contenido ... seguramente el Contenido es el propietario de la imagen. De la guía:

La distinción es en donde se colocan la clave externa (que va en la mesa para la clase que declara la belongs_to asociación), pero debe darle una cierta pensar en el significado real de los datos también. La relación has_one dice que algo es algo tuyo: es decir, que algo apunta a tú.

Finalmente, no estoy seguro de que necesite tanto los contenidos como las imágenes para tener claves foráneas. Mientras las imágenes hagan referencia al content_id, creo que estás bien.

Cuestiones relacionadas