在Rails中实现标记:如何使用一个标记引用多个项目?

时间:2011-08-11 19:04:49

标签: ruby-on-rails tags has-and-belongs-to-many

我正在使用rails编写博客引擎,并设置了一个标签模型和一个具有have_and_belongs_to_many关系的帖子模型。标记添加工作正常,在查找具有特定标记的所有帖子时会出现问题:

如果我将标签“test”添加到帖子A,然后将标签“test”添加到帖子B,则有两个标签对象,两者都具有名称“test”但具有不同的ID,两者都引用不同的帖子。现在,如果我有一个控制器动作indexTagPosts,它接受参数“tag”并查找带有该标签的所有帖子,它将只返回一个帖子,因为另一个标签具有不同的ID并且没有真正关联。我应该以某种方式限制添加新标签,还是应该操纵我以不同方式拉出所有相关标签的方式?

以下是控制器操作,它应该根据参数'tag'获取所有相关帖子:

def indexTagPosts

        @tag = Tag.find(params[:tag])
        @posts = @tag.posts.all

end

以下是保存标记的操作:

def create


    @post = Post.find(params[:post_id])
    @tag = @post.tags.create(params[:tag])

    respond_to do |format|
      if @tag.save
        format.html { redirect_to edit_post_path(@post),:notice => "Success" }
      end
    end  

end

提前致谢并对冗余或不良措辞道歉。

1 个答案:

答案 0 :(得分:9)

我希望我知道每个人都有使用has_and_belongs_to_many的想法,因为这是一个非常难以管理的事情,即使它在开始时看起来很简单。更好的方法是建立has_many ..., :through类型关系,因为您可以轻松管理各个链接并向其添加元数据。

例如,这是一个简单的双向连接和一个中间模型,你会发现一个经常发生的模式:

class Post < ActiveRecord::Base
  has_many :post_tags
  has_many :tags, :through => :post_tags
end

class Tag < ActiveRecord::Base
  has_many :post_tags
  has_many :posts, :through => :post_tags
end

class PostTag < ActiveRecord::Base
  belongs_to :post
  belongs_to :tag
end

此时添加和删除标记链接很简单:

@post = Post.find(params[:post_id])

if (params[:tags].present?)
  @post.tags = Tag.where(:name => params[:tags].split(/\s*,\s*/))
else
  @post.tags = [ ]
end

has_many关系管理器将根据需要创建,更新或销毁PostTag关联模型。

通常,您会发展Post模型,以包含一个实用程序方法,用于使用您喜欢的任何分隔符检索和分配标记:

 class Post
   def tags_used
     self.tags.collect(&:name).join(',')
   end

   def tags_used=(list)
     self.tags = list.present? ? Tag.where(:name => list.split(/\s*,\s*/)) : [ ]
   end
 end