我是ruby和ruby-on-rails的新手。我需要实现复杂的标记引擎:
每个标签可以包含0个或更多个同义词(是的,就像在SO上一样)
应该有一个层次结构标签:即有子标签和超级标签。说,我有三个标签:programming
,ruby
和c
。然后,programming
是ruby
和c
的超级标记,当我为项目输入关于ruby的标记时,没有必要输入标记programming
,我可以仅使用ruby
标记。当我输入标签时,应该递归添加所有超级标签。 (实际上很奇怪,我从来没有见过任何带有此功能的标签引擎,我真的感觉不够用它)
每个用户都应拥有自己的一组标记,即每个Tag
belongs_to
User
。标签不对任何人公开,它们对其所有者是私有的。
似乎我不能使用acts_as_taggable_on
宝石,对吗?所以我必须实现自己的。实际上我已经实现了Tag
类,它支持层次结构,同义词和用户的东西,它似乎有效。但是如何制作可以用它标记的东西还有很多问题。
我正在尝试对acts_as_taggable_on
进行逆向工程,这对像我这样的新手来说真的很复杂..
所以,有很多问题,但我现在会更具体:
假设我有一个类Item
,我希望它可以被标记。据我了解,我应该在has_many :through
和Item
方使用Tag
关联。因此,创建包含item_id
和tag_id
字段的中间表。
但是:我希望我的标记引擎具有通用性!因此,我不想将与Tag
相关的任何内容添加到Item
模型。
所以,唯一真正的问题是:通常只能在has_many :through
方创建Item
关联吗?
其次,如果有人对我解释过的东西有一些建议,我很乐意看到它们。
答案 0 :(得分:2)
我可以向你推荐一些可能对你的大部分问题陈述有帮助的事情。
应该有标签层次结构
可以使用自引用has_many关联 Creating a model that has a tree structure
class Tag < ActiveRecord::Base
has_many :sub_tags, class_name: "Tag", :foreign_key => "super_tag_id"
belongs_to :super_tag, class_name: "Tag"
end
我希望我的标记引擎具有通用性!所以我不想添加任何与Item
相关的Tag模型标记应该是多态的,因为它广泛适用于使用。
class TaggedItem < ActiveRecord::Base
belongs_to :tag
belongs_to :taggable, polymorphic: true
end
创建has_many通常是否可以:仅通过物品方面的关联?
我想是的,has_may through
是要走的路。因此,您的Item
模型可能看起来像
class Item < ActiveRecord::Base
has_many :tags, as: :taggable, through: :tagged_items
end
答案 1 :(得分:1)
除了swapnilabnave的好答案外,我还会解释你在寻找什么:
我建议将您的问题分解为更多模块化问题
您的问题是,您是否可以使用has_many :through
表示关系。正如所解释的那样,答案是“是”,但这并不能完全解决问题
标记层次结构
如上所述,您的代码将包含“父母”和其他商品
虽然我在Rails中没有丰富的经验,但在CakePHP中,这将被称为tree structure。 CakePHP通过3列 - parent_id
,left
,right
来处理这个问题。这些基本上允许应用程序根据这3列
在您的情况下,我建议在parent_id
数据库中添加tags
列,如果需要,您可以为其分配超级标记(似乎您只有一个超级-tag每个标签?)。您可以使用swapnilabnave发布的self-referencing association技术在您的模型中处理此问题,以便能够像这样调用super_tag
:
@tag.super_tag
重要的是,如果每个标签只能有一个super_tag
,那么这只会有效。如果你想为每个标签提供无限数量的超级标签,你可以这样做:
class Tag < ActiveRecord::Base
has_many :sub_tags, class_name: "Tag", :foreign_key => "super_tag_id"
has_many :tag_super_tags, class_name: "TagSuperTag", :foreign_key => "super_tag_id"
has_many :super_tags, :through => :tag_super_tags
end
Class TagSuperTag
belongs_to :tag
belongs_to :super_tag, :class => "Tag"
end
虽然我不确定连接模型代码是否有效,但希望能在这里向您展示这个想法。这将创建一个名为TagSuperTag的自引用连接模型,并允许您拥有这样的表:
tag_super_tags
id | tag_id | super_tag_id | created_at | updated_at
tags (no need for super_tag_id)
id | user_id | name | etc
这将允许您为每个标签添加任意数量的超级标签
用户有很多标签
因为每个用户都有很多标签,所以您可以使用标准has_many
关联,如下所示:
class User < ActiveRecord::Base
has_many :tags
end
class Tag < ActiveRecord::Base
belongs_to :user
end
这意味着每个代码都必须有user_id
列,才能充当foreign_key
标签是通用的
使标签具有通用性(不只是item
)需要polymorphic association
,而且似乎是一个连接模型
正如swapnilabnave所描述的那样,任何想用它来存储标签的模型都可以访问这个连接模型,从而允许你将任何模型与它相关联。这是你如何做到这一点:
class TaggedItem < ActiveRecord::Base
belongs_to :taggable, polymorphic: true
belongs_to :tag
end
tagged_items
id | taggable_type | taggable_id | tag_id | created_at | updated_at
这将允许您从任何其他模型引用此模型,如下所示:
class Post < ActiveRecord::Base
has_many :tagged_items, :class_name => "TaggedItem", :as => :taggable, :dependent => :destroy
has_many :tags, :through => :tagged_items
end
class Email < ActiveRecord::Base
has_many :tagged_items, :class_name => "TaggedItem", :as => :taggable, :dependent => :destroy
has_many :tags, :through => :tagged_items
end
Tag
模型也应该has_many :tagged_items
:
class Tag < ActiveRecord::Base
has_many :tagged_items, :class_name => "TaggedItem", :foreign_key => "tag_id", :dependent => :destroy
end
希望这有帮助