我有一个类似于博客的rails项目,其帖子包含一组图像和一个特色图像。图像集是一个非常直接的HABTM关系,因为几个帖子可以共享相同的图像,一个帖子可以有很多图像,但特色图像有点麻烦。
每个帖子都应该有一个且只有一个特色图片,一个图片可以是几个帖子上的精选图片,所以我的第一个想法就是扭转关系,让图片has_many
发帖和帖子{{1}图像,但这在很多不同的方面似乎有问题。首先,它不是很语义。其次,post控制器需要额外的代码来接受image_id的值,因为Post.new似乎不想接受image_id作为属性。
我的第二个想法 - 这是我到目前为止的一个想法 - 是在帖子的belong_to
和limit: 1
上使用has_and_belongs_to_many :featured_images
说明符来使用HABTM关系迁移中的unique: true
上的{1}}这个解决方案有效,但看起来很糟糕。此外,这意味着我必须访问此t.belongs_to :post
而不是post.featured_images.first
的精选图片。更糟糕的是,我不得不认为这会损害数据库性能,因为它必须访问三个表而不是两个表,并且它必须在多对多表中搜索post id,而不是通过id进行即时识别列。
那么,这是正确的做法还是有更好的方法? rails是否有post.featured_image
,has_one
关系?
答案 0 :(得分:3)
为什么不尝试类似的东西(没有HABTM,只有has_many):
class Image < ActiveRecord::Base
belongs_to :post
attr_accessible :featured
after_commit :reset_featured, if: :persisted?
protected
# garant that featured will be only one
def reset_featured
Image.where('id <> ?', self.id).update_all(featured: false) if self.featured
end
end
class Post < ActiveRecord::Base
has_many :images, conditions: { featured: false }
has_one :featured_image, class_name: 'Image', conditions: { featured: true }
end
答案 1 :(得分:1)
由于这是一个“拥有并且属于许多”关系的情况,但是你想要存储关于关系本身的额外信息(事实上图像是“特色”的帖子),我会尝试而是has_many :through
安排。像这样:
class Post < ActiveRecord::Base
has_many :post_images, inverse_of: :post
has_many :images, through: :post_images
has_one :featured_post_image, class_name: PostImage,
inverse_of: :post, conditions: { is_featured: true }
has_one :featured_image, through: :featured_post_image
accepts_nested_attributes_for :post_images, allow_destroy: true
attr_accessible :post_images_attributes
end
class PostImage < ActiveRecord::Base
belongs_to :post
belongs_to :image
attr_accessible :image_id
end
class Image < ActiveRecord::Base
has_many :post_images
has_many :posts, through: :post_images
end
不幸的是,添加验证以确保帖子永远不会有多个精选图片比看起来更棘手。您可以对Post
进行验证,但如果您的应用的其他部分直接创建PostImages而不触及相关帖子,则无法保存。如果有人读到这篇文章对这个问题有一些了解,我很乐意听到它。