Rails – 多态collections夹(用户可以喜欢不同型号)
我们正在尝试添加多个可接受的对象,用户可以在其中collections许多不同的对象,但不确定如何使其工作。
这是最喜欢的型号:
class Favorite < ActiveRecord::Base # belongs_to :imageable, polymorphic: true belongs_to :user belongs_to :category belongs_to :business belongs_to :ad_channel belongs_to :location belongs_to :offer end
用户模型:
class User < ActiveRecord::Base has_many :favorites, as: :favoritable end
还有一个可以collections的示例模型:
class Category < ActiveRecord::Base has_many :sub_categories has_many :ad_channels has_many :offers belongs_to :favoritable, polymorphic: true end
我不确定这是否设置正确,这是我们首先需要一些反馈。
其次,我们如何为用户“喜欢”某些东西?
这是我们到目前为止尝试过的失败:
@user.favorites << Category.find(1)
编辑:这还需要一个collections数据库表来记录事物吗? 这对我们来说是一个非常新的概念。
模型关系
您Favorite
型号如下所示:
class Favorite < ActiveRecord::Base belongs_to :favoritable, polymorphic: true belongs_to :user, inverse_of: :favorites end
然后,您的User
模型将如下所示:
class User < ActiveRecord::Base has_many :favorites, inverse_of: :user end
然后,可以collections的模型应如下所示:
class Category < ActiveRecord::Base has_many :favorites, as: :favoritable end
是的,您需要在数据库中使用favorites
表。
collections物品
所以,这应该允许你做的事情:
@user.favorites << Favorite.new(favoritabe: Category.find(1)) # add favorite for user
请记住,您需要将Favorite
实例添加到@user.favorites
,而不是favoritable
模型的实例。 最favoritable
模型是Favorite
的实例的属性。
但是,实际上,在Rails中执行此操作的首选方法是这样的:
@user.favorites.build(favoritable: Category.find(1))
寻找某种类型的collections夹
如果您只想找到某种类型的collections夹,您可以执行以下操作:
@user.favorites.where(favoritable_type: 'Category') # get favorited categories for user Favorite.where(favoritable_type: 'Category') # get all favorited categories
如果您经常这样做,我认为将范围添加到多态模型非常简洁:
class Favorite < ActiveRecord::Base scope :categories, -> { where(favoritable_type: 'Category') } end
这允许你这样做:
@user.favorites.categories
哪个从上面获得与@user.favorites.where(favoritable_type: 'Category')
相同的结果。
允许用户仅collections一次项目
我猜你可能也想让用户只能一次collections一个项目,这样当你做@user.favorites.categories
类的事情时,你就不会得到重复的类别。 以下是如何在Favorite
模型上进行设置:
class Favorite < ActiveRecord::Base belongs_to :favoritable, polymorphic: true belongs_to :user, inverse_of: :favorites validates :user_id, uniqueness: { scope: [:favoritable_id, :favoritable_type], message: 'can only favorite an item once' } end
这使得collections夹必须具有user_id
, favoritable_id
和favoritable_type
的唯一组合。 由于将favoritable_id
和favoritable_type
组合在一起以获得最受欢迎的项目,因此这相当于指定所有collections夹必须具有user_id
和favoritable
的唯一组合。 或者,用简单的英语,“用户只能喜欢一次”。
将索引添加到数据库
出于性能原因,当您具有多态关系时,您需要_id
和_type
列上的数据库索引。 如果您使用带有多态选项的Rails生成器,我认为它会为您执行此操作。 否则,你必须自己做。
如果您不确定,请查看您的db/schema.rb
文件。 如果您在favorites
表的架构之后有以下内容,那么您已全部设置:
add_index :favorites, :favoritable_id add_index :favorites, :favoritable_type
否则,将这些行放在迁移中并运行那个坏孩子。
当你在它时,你应该确保所有外键也有索引。 在此示例中,这将是favorites
表上的user_id
列。 同样,如果您不确定,请检查您的架构文件。
关于数据库索引的最后一件事:如果要添加上面一节中概述的唯一性约束,则应该为数据库添加唯一索引。 你会这样做:
add_index :favorites, [:favoritable_id, :favoritable_type], unique: true
这将强制执行数据库级别的唯一性约束,如果您有多个应用程序服务器都使用单个数据库,这通常只是正确的方法。