acts-as-taggable-on 生成标签

step1:安装gem

把下面这句话放入Gemfile中

1
gem 'acts-as-taggable-on'

step2.在终端(terminal)中执行

1
2
3
bundle install
rake acts_as_taggable_on_engine:install:migrations
rake db:migrate

这会生成tags和taggings这两张表。在schema.rb中可以查看。

step3.在自己需要加标签的model中加入

1
2
3
class Post < ActiveRecord::Base
acts_as_taggable_on :tags
end

在rails console中可以执行看看效果

1
2
3
post = Post.create
post.tag_list = "programming, ruby, rails"
post.tag_list

执行结果:

1
['programming', 'ruby', 'rails']

新增时tag_list是一个以逗号相隔的string(字符串),在新增tag的时候,只需填入tag的名称,以逗号相隔做成字符串,后面的一系列操作这个gem自动都给你处理了。

(会通过taggings这个表连接tags和posts的关系,而且仔细看tags的表结构可以看到name: “index_tags_on_name”, unique: true,也就是tags的name字段是唯一的,所以不会重复添加同名的标签)

step4:post_controller

在新增post的时候,把tag_list加入Strong Parameters(强校验)

1
2
3
4
5
6
7
8
9
class PostsController < ApplicationController
...
private
def post_params
params.require(:post).permit(:title, :content, :tag_list)
end
end

step5.配置路由

config/routes.rb

1
2
3
4
Rails.application.routes.draw do
resources :posts
resources :tags, only: [:index, :show]
end

step6. 以下是view,可以参考一下

app/views/posts/_form.html.erb (在新增post时候加入tag_list即可。如果想做成下拉框select标签时,请注意,强校验不会接受hash类型,并且tag_list也只能是逗号相隔的字符串才行,所以,要在强校验之前,把tag_list处理成相应格式)

1
2
3
4
5
6
<%= form_for post do |f| %>
<%= f.text_field :title %>
<%= f.text_area :body %>
<%= f.text_field :tag_list %>
<%= f.submit %>
<% end %>

app/controllers/tags_controller.rb

1
2
3
4
5
6
7
8
9
10
class TagsController < ApplicationController
def index
@tags = ActsAsTaggableOn::Tag.all
end
def show
@tag = ActsAsTaggableOn::Tag.find(params[:id])
@posts = Post.tagged_with(@tag.name)
end
end

app/views/acts_as_taggable_on/tags/_tag.html.erb

1
<%= link_to tag.name, tag_path(tag) %>

app/views/tags/index.html.erb

1
2
<h1>Tags</h1>
<%= render @tags %>

app/views/tags/show.html.erb

1
2
<h1><%= @tag.name %></h1>
<div><%= render @posts %></div>

app/views/posts/_post.html.erb

1
<h2><%= link_to post.title, post_path(post) %></h2>

app/views/posts/index.html.erb

1
2
<h1>Posts</h1>
<%= render @posts %>

app/views/posts/index.html.erb

1
2
3
4
<%= post.title %>
<%= post.content %>
<h4>Tags</h4>
<%= render post.tags %>

app/views/posts/show.html.erb

1
2
3
<h1><%= @post.title %></h1>
<div><%= @post.body %></div>
<div><%= render @post.tags %></div>

补充:

1
2
@tags = current_user.tags
@hot_tags = Tag.where.not(id:@tags)

用这个筛选掉已经关注的的tags(在这个地方纠结,想通过Tag.all-@tags,但是没有成功。有可能是@tags gem做了什么关联,查出来的对象不一致,或者是不能用减做对象的集合操作,有待查证)

1
2
3
#取消标签
current_user.tag_list.remove(@tag.name)
current_user.save

新增单个标签

1
2
3
@tag = Tag.find(params[:id])
current_user.tag_list.add(@tag.name)
current_user.save

新增多个标签,参数是数组形式时

1
2
3
4
5
6
7
tag_list = params[:tag_list]
if tag_list
#数组要转成逗号相隔的字符串
tag_list = tag_list.map{|k,v| "#{k}#{v}"}.join(',')
current_user.tag_list = tag_list
current_user.save
end