Rails - 多态收藏夹(用户可以喜欢不同的型号)

时间:2014-02-16 21:37:59

标签: ruby-on-rails rails-activerecord polymorphic-associations activemodel

我们正在尝试添加多个可接受的对象,用户可以在其中收藏许多不同的对象,但不确定如何使其工作。

以下是收藏夹型号:

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

可以收藏的一些示例模型:

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)
编辑:这还需要一个收藏数据库表来记录事物吗?这对我们来说是一个非常新的概念。

1 个答案:

答案 0 :(得分:15)

模型关系

您的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

然后,可以收藏的模型应如下所示:

class Category < ActiveRecord::Base
  has_many :favorites, as: :favoritable
end

是的,您的数据库中需要一个favorites表。

收藏物品

所以,这应该允许你做这样的事情:

@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))

寻找某种类型的收藏

如果您只想查找某种类型的收藏,可以执行以下操作:

@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')相同的结果。

仅允许用户收藏项目

我猜你可能也想让用户只能一次收藏一个项目,这样当你做@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

这使得收藏夹必须具有user_idfavoritable_idfavoritable_type的唯一组合。由于favoritable_idfavoritable_type被合并以获得优惠项,因此这相当于指定所有收藏夹必须具有user_idfavoritable的唯一组合。或者,用简单的英语,“用户只能喜欢一次”。

向数据库添加索引

出于性能原因,当您具有多态关系时,您需要_id_type列上的数据库索引。如果您使用带有多态选项的Rails生成器,我认为它会为您执行此操作。否则,你必须自己做。

如果您不确定,请查看您的db/schema.rb文件。如果您在favorites表的架构之后有以下内容,那么您已全部设置:

add_index :favorites, :favoritable_id
add_index :favorites, :favoritable_type

否则,将这些行放入迁移并运行那个坏孩子。

当你遇到它时,你应该确保所有外键都有索引。在此示例中,这将是user_id表上的favorites列。同样,如果您不确定,请检查您的架构文件。

关于数据库索引的最后一件事:如果 要添加上面一节中概述的唯一性约束,则应该为数据库添加唯一索引。你会这样做:

add_index :favorites, [:favoritable_id, :favoritable_type], unique: true

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