0

Я пытался выяснить, как связать свои модели с проектом, над которым я работал некоторое время, и я пришел сюда за помощью пару раз раньше, но у меня никогда не было удовлетворительного ответа. У меня две модели: Post и Image. Каждая запись имеет несколько изображений, прикрепленных к нему и сообщениям могут обмениваться изображениями, поэтому отношения HABTM имели смысл, что, как это:Rails признакам ассоциации изображений?

class Post < ActiveRecord::Base 
    has_and_belongs_to_many :images 
end 

class Image < ActiveRecord::Base 
    has_and_belongs_to_many :posts 
end 

Сейчас проблема заключается в том, что я хочу, чтобы каждый пост, чтобы иметь один «признаки изображения. ' Как мне это сделать? Первой мыслью, которая приходит на ум, является простой has_one :featured_image на столбе и belongs_to :post_featured_on на изображении, но проблема в том, что одно и то же изображение может отображаться на нескольких сообщениях.

Итак, следующая идея, которую я придумал, заключается в том, чтобы обратить вспять отношения: belongs_to :featured_image на сообщение и has_many :posts_featured_on на изображение. Проблема в том, что он не очень семантический, и рельсы, похоже, не хотят позволять мне устанавливать отображаемое изображение из его формы, как это в контроллере: Post.new(:featured_image => Image.find(params[:image_id]))

Итак, следующая идея мне предложила было вторым отношением HABTM, например: has_and_belongs_to_many :featured_images. Там есть очевидная проблема, это множественное число. Я попытался поставить unique: true в столбец post_id в процессе миграции, но это не помогло мне в том, что я продолжал делать это в своем коде: post.featured_images.first, что может быть очень неприятно.

Последняя идея, которую я попытался было has_many :posts, through: :attachment и has_one :featured_posts, through: :attachment вместо оригинального HABTM, но это только кажется излишне громоздким, и рельсы, кажется, не хочет меня назначить изображений на лету так, как Post.new(:featured_image => Image.find(params[:image_id])).

Есть ли хороший способ сделать это? Я сделал что-то не так в моих предыдущих попытках? Разве это не просто простой внешний ключ на стол стол? Почему это должно быть так сложно?

ответ

1

Мне нравится ваша вторая идея просто отлично. Полностью раздутый подход заключается в использовании модели транзакций, например, предлагаемой @depa. Модель транзакции великолепна, если вы хотите сохранить дополнительные атрибуты, например, когда изображение было создано для данного сообщения (и, возможно, когда оно не было). Но, независимо от того, строите ли вы этот объект транзакции или нет, вы можете просто кэшировать отображаемое изображение на пост-объекте для быстрого доступа. Попробуйте просто сделать это:

class Post < ActiveRecord::Base 
    has_and_belongs_to_many :images 
    belongs_to :featured_image, class_name: 'Image' 
end 

class Image < ActiveRecord::Base 
    has_and_belongs_to_many :posts 
    # Purposefully not defining an inverse relationship back to Post. 
    # You can if you need or want it but you may not. 
end 

Затем в контроллере я бы рекомендовал:

@post = Post.find_by_id(params[:id]) 
@post.featured_image = Image.find(params[:image_id]) 
@post.save 

Вы, вероятно, не имели успеха с этим, прежде чем из-за не имея attr_accessible :featured_image_id на модели Post. И/или потому, что вы использовали неправильное имя атрибута. (Это должно было быть Post.new(featured_image_id: Image.find(params[:image_id])).) В любом случае, полезно держать код немного более объектно-ориентированным, чем все это. Как я это описал выше, вам не нужно думать о имени столбца в базе данных и просто думать об объектах, с которыми вы имеете дело. I.e, просто назначьте ссылку Image на ссылку feature_image. Помня об этом, я предпочитаю не устанавливать внешние ключи как attr_accessible, когда это возможно.

+0

Мне это нравится, но мне не нравится откормить контроллер. Кстати, я использую Rails 4, поэтому нет attr_accessible. –

+0

Это то, что я собираюсь. –

0

Вы можете делать то, что хотите, используя has_one: через объединение.

class Post < ActiveRecord::Base 
    has_and_belongs_to_many :images 
    has_one     :featured_image, 
          :through => :feature, 
          :class_name => 'Image' 
    has_one     :feature 
end 

class Image < ActiveRecord::Base 
    has_and_belongs_to_many :images 
    has_many    :featured_images, 
          :through => :features, 
          :class_name => 'Image', 
          :foreign_key => :featured_image_id 
    has_many    :features 
end 

class Feature < ActiveRecord::Base 
    belongs_to    :featured_image, 
          :class_name => 'Image' 
    belongs_to    :post 
end 
Смежные вопросы