Подтвердить что ты не робот

Rails has_one vs принадлежит к семантике

У меня есть модель, представляющая элемент Content, который содержит некоторые изображения. Количество изображений фиксировано, так как эти ссылки на изображения очень специфичны для содержимого. Например, модель Content относится к модели Image дважды (изображение профиля и фоновое изображение). Я пытаюсь избежать общего has_many и придерживаться нескольких has_one. Текущая структура базы данных выглядит так:

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

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

Я просто не могу понять, как правильно настроить ассоциации здесь. Модель Content может содержать две ссылки belongs_to для Image, но это не кажется семантически правильным, потому что в идеале изображение принадлежит содержимому, или, другими словами, контент имеет два изображения.

Это лучшее, что я мог подумать (сломав семантику):

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

У меня нет выхода, и есть ли лучший способ достичь этой ассоциации?

4b9b3361

Ответ 1

Простой ответ заключается в настройке ваших ассоциаций в обратном порядке, как у вас:

# 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

Вам вообще не нужны внешние символы 'background_image_id' и 'profile_image_id' в таблице содержимого.

Однако существует более элегантное решение: однонаправленное наследование таблицы. Настройте его сейчас, если вы хотите, чтобы в будущем фоновые изображения и изображения профилей несколько отличались друг от друга, а также теперь прояснит ваш код.

Сначала добавьте столбец в таблицу изображений, называемую type:

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

Теперь настройте свои модели следующим образом:

# 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

Теперь вы можете делать всевозможные вещи, например, получать список всех фоновых изображений:

# script/console
BackgroundImage.all

Это более верно для модели данных, которую вы пытаетесь создать, позволяет в будущем легче всего расширять возможности и предлагает вам несколько новых современных методов.

UPDATE:

С тех пор я создал статью в блоге под названием "Наследование на основе одиночных таблиц с тестами" , которая идет более подробно и охватывает тестирование.

Ответ 2

На основе руководства ассоциаций AR, я думаю, вы должны использовать has_one. Для изображения не имеет смысла владеть контентом... контент, безусловно, принадлежит изображению. Из руководства:

Различие заключается в том, где вы размещаете внешний ключ (он идет на стол для класса, объявляющего свойство belongs_to ассоциация), но вы должны дать некоторые думал о реальном значении данных. Отношение has_one говорит, что одно из вас - ваше - то есть что-то указывает на вы.

Наконец, я не уверен, что вам нужно как содержимое, так и изображения иметь внешние ключи. Пока изображения ссылаются на content_id, я думаю, что все в порядке.