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_idfavoritable_idfavoritable_type的唯一组合。 由于将favoritable_idfavoritable_type组合在一起以获得最受欢迎的项目,因此这相当于指定所有collections夹必须具有user_idfavoritable的唯一组合。 或者,用简单的英语,“用户只能喜欢一次”。

将索引添加到数据库

出于性能原因,当您具有多态关系时,您需要_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 

这将强制执行数据库级别的唯一性约束,如果您有多个应用程序服务器都使用单个数据库,这通常只是正确的方法。