Rails-变形收藏夹(用户可以收藏不同的模型) [英] Rails - Polymorphic Favorites (user can favorite different models)
问题描述
我们正在尝试添加多个收藏夹对象,用户可以在其中收藏许多不同的对象,但不确定如何使它起作用.
We are trying to add multiple favoritable objects, where a user can favorite many different objects, but are not sure how to make it work.
这是收藏夹"模型:
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
还有一个可以收藏的东西的示例模型:
And one example model of something that can be favorited:
class Category < ActiveRecord::Base
has_many :sub_categories
has_many :ad_channels
has_many :offers
belongs_to :favoritable, polymorphic: true
end
我不确定此设置是否正确,这将是我们需要反馈的第一件事.
I'm not sure if this is set up properly so that would be the first thing we need some feedback on.
第二,我们如何为用户收藏"某些东西?
Secondly how do we "favorite" something for a user?
这是我们迄今为止尝试失败的结果:
This is what we've tried so far unsuccessfully:
@user.favorites << Category.find(1)
另外,这是否需要收藏夹数据库表来记录内容?对我们来说,这是一个非常新的概念.
Also will this need a favorites database table to record things? This is a pretty new concept for us.
推荐答案
模型关系
您的Favorite
模型如下所示:
class Favorite < ActiveRecord::Base
belongs_to :favoritable, polymorphic: true
belongs_to :user, inverse_of: :favorites
end
然后,您的User
模型将如下所示:
Then, your User
model will look like this:
class User < ActiveRecord::Base
has_many :favorites, inverse_of: :user
end
然后,可以收藏的模型应如下所示:
Then, the models that can be favorited should look like this:
class Category < ActiveRecord::Base
has_many :favorites, as: :favoritable
end
是的,您的数据库中将需要一个favorites
表.
Yes, you will need a favorites
table in your database.
因此,这应该允许您执行以下操作:
So, this should allow you to do stuff like:
@user.favorites << Favorite.new(favoritabe: Category.find(1)) # add favorite for user
请记住,您需要将Favorite
的实例添加到@user.favorites
,而不是favoritable
模型的实例. favoritable
模型是Favorite
实例的属性.
Just keep in mind that you need to add instances of Favorite
to @user.favorites
, not instances of favoritable
models. The favoritable
model is an attribute on the instance of Favorite
.
但是,实际上,在Rails中执行此操作的首选方式是这样的:
But, really, the preferred way to do this in Rails is like so:
@user.favorites.build(favoritable: Category.find(1))
查找某种收藏夹
如果您只想查找某种类型的收藏夹,则可以执行以下操作:
Finding Favorites of a Certain Kind
If you wanted to find only favorites of a certain type, you could do something like:
@user.favorites.where(favoritable_type: 'Category') # get favorited categories for user
Favorite.where(favoritable_type: 'Category') # get all favorited categories
如果您要经常执行此操作,我认为将范围添加到多态模型中非常干净:
If you're going to do this often, I think adding scopes to a polymorphic model is pretty clean:
class Favorite < ActiveRecord::Base
scope :categories, -> { where(favoritable_type: 'Category') }
end
这允许您执行以下操作:
This allows you to do:
@user.favorites.categories
从上方获得与@user.favorites.where(favoritable_type: 'Category')
相同的结果.
Which is gets you the same result as @user.favorites.where(favoritable_type: 'Category')
from above.
我猜测您可能还希望只允许用户收藏一个项目一次,这样,当您执行@user.favorites.categories
之类的操作时就不会出现重复的类别.在您的Favorite
模型上进行设置的方法如下:
I'm guessing that you might also want to allow users to only be able to favorite an item once, so that you don't get, for example, duplicate categories when you do something like, @user.favorites.categories
. Here's how you would set that up on your Favorite
model:
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_id
,favoritable_id
和favoritable_type
的唯一组合.由于将favoritable_id
和favoritable_type
组合在一起以获得最喜欢的项目,所以这等效于指定所有收藏夹必须具有user_id
和favoritable
的唯一组合.或者用简单的英语说,用户只能收藏一次东西."
This makes it so that a favorite must have a unique combination of user_id
, favoritable_id
, and favoritable_type
. Since favoritable_id
and favoritable_type
are combined to get the favoritable item, this is equivalent to specifying that all favorites must have a unique combination of user_id
and favoritable
. Or, in plain English, "a user can only favorite something once".
出于性能原因,当您具有多态关系时,需要在_id
和_type
列上使用数据库索引.如果您将Rails生成器与多态选项一起使用,我认为它将为您完成此任务.否则,您必须自己做.
For performance reasons, when you have polymorphic relationships, you want database indexes on the _id
and _type
columns. If you use the Rails generator with the polymorphic option, I think it will do this for you. Otherwise, you'll have to do it yourself.
如果不确定,请查看您的db/schema.rb
文件.如果favorites
表的模式后面有以下内容,则说明一切就绪:
If you're not sure, take a look your db/schema.rb
file. If you have the following after the schema for your favorites
table, then you're all set:
add_index :favorites, :favoritable_id
add_index :favorites, :favoritable_type
否则,将这些行放入迁移中并运行那个坏孩子.
Otherwise, put those lines in a migration and run that bad boy.
使用它时,应确保所有外键都具有索引.在此示例中,这将是favorites
表上的user_id
列.同样,如果不确定,请检查您的架构文件.
While you're at it, you should make sure that all of your foreign keys also have indexes. In this example, that would be be the user_id
column on the favorites
table. Again, if you're not sure, check your schema file.
关于数据库索引的最后一件事:如果要按照上节所述添加唯一性约束,则应该向数据库中添加唯一索引.您将这样做:
And one last thing about database indexes: if you are going to add the uniqueness constraint as outlined in the section above, you should add a unique index to your database. You would do that like this:
add_index :favorites, [:favoritable_id, :favoritable_type], unique: true
这将在数据库级别强制执行唯一性约束,如果您有多个应用程序服务器都使用一个数据库,则这是必需的,并且通常是正确的处理方式.
This will enforce the uniqueness constraint at the database level, which is necessary if you have multiple app servers all using a single database, and generally just the right way to do things.
这篇关于Rails-变形收藏夹(用户可以收藏不同的模型)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!