読者です 読者をやめる 読者になる 読者になる

Rails Webook

自社のECを開発している会社で働いています。Rails情報やサービスを成長させる方法を書いていきます

Railsでacts-as-taggable-onを使ってタグ管理を行う

Rails中級 Rails Model Rails gem

f:id:nipe880324:20150224135234j:plain:w480
Flickr: cambodia4kidsorg's Photostream

acts-as-taggable-onはタグの追加、削除、関連するオブジェクトの取得、タグクラウドなどのタグを管理するためのgemです。

今回は、Railsでacts-as-taggable-onでタグ管理を行う方法について説明します。


動作確認

  • Ruby 2.2.0
  • Rails 4.2.0
  • acts-as-taggable-on 3.4.4

目次

  1. acts-as-taggable-onのインストール
  2. acts-as-taggable-onの基本的な使い方
  3. acts-as-taggable-onを使ってユーザー管理にタグ機能を実装してみる
  4. Bootstrap Tags Inputを使ってユーザーのタグ入力を簡易にする
  5. 同じタグを保持しているユーザーを表示する


1. acts-as-taggable-onのインストール

Gemfileに追加します。

# Gemfile
gem 'acts-as-taggable-on', '~> 3.4'


バンドルを実行します。

bunlde


acts-as-taggable-onで必要なテーブルを作成します。

bin/rake acts_as_taggable_on_engine:install:migrations
bin/rake db:migrate


2. acts-as-taggable-onの基本的な使い方

モデルファイルにacts_as_taggable_onを追加します。

class Post < ActiveRecord::Base
  acts_as_taggable_on :labels # post.label_list が追加される
  acts_as_taggable            # acts_as_taggable_on :tags のエイリアス
end


上記のように設定することで、以下の2つのメソッドを利用することができます。

post.label_list
post.tag_list


次のようにして、タグの追加、取得、設定、削除ができます。

# タグの追加
post.tag_list.add("programming")  # "Programming"タグを追加する
post.tag_list.add("tips", "hardware") # 複数のタグを追加する
post.save

post.label_list # tag_listだけでなく、別のタグリストのlabel_listにもアクセス可能です


# タグの取得
post.tag_list #=> ["programming", "tips", "hardware"]


# タグの設定(上書きされる)
post.tag_list = ["programming", "tips"] # "a,b"といったカンマ区切りの文字列でも入力可能
post.tag_list #=> ["programming", "tips"]


# タグの削除
post.tag_list.remove("programming") # "programming"タグを削除する
post.tag_list.clear                 # すべてのタグを削除する


「最も使われているタグ」と「最も使われていないタグ」を取得できます。
デフォルトで20件取得します。引数で件数を指定することで取得するを変更できます。

# 最も使われているタグを配列で取得
ActsAsTaggableOn::Tag.most_used
ActsAsTaggableOn::Tag.most_used(3)

# 最も使われていないタグを配列で取得
ActsAsTaggableOn::Tag.least_used
ActsAsTaggableOn::Tag.least_used(3)


tagged_withメソッドで、特定のタグでPostを検索するができます。

# programmingのタグがつけられているPostを取得する
posts = Post.tagged_with("programming")

# programmingとjavascriptタグがつけれれているPostを取得する
# :match_all (AND条件), :any (OR条件), :exclued (NOT条件)が使える
posts = Post.tagged_with(["programming", "javascript"], match_all: true)


find_related_skillsメソッドで、同じタグを持ったPostを検索することができます。

@post.find_related_skill #=> [<Post ...>, <Post ...>]


3. acts-as-taggable-onを使ってユーザー管理にタグ機能を実装してみる

ここからは、acts-as-taggable-onを使って、次のようにRailsでユーザー管理にタグ機能を追加するようにしてみます。
f:id:nipe880324:20150224140517j:plain:w480


まず、ユーザーをScaffoldで作成します。

bin/rails g scaffold User name
bin/rake db:migrate


次に、Userモデルにskillsinterestsといった2つのタグリストを追加します。

# app/models/user.rb
class User < ActiveRecord::Base
  acts_as_ordered_taggable_on :skills, :interests
end


次に画面からそれぞれのタグリストをテキストフィールドでカンマ区切りで入力できるようにします。

<!-- app/views/users/_form.html.erb -->
<%= form_for(@user) do |f| %>
  ...
  <div class="field">
    <%= f.label :name, "名前" %><br>
    <%= f.text_field :name %>
  </div>
  <div class="field">
    <%= f.label :skill_list, "スキル・特技(カンマ区切り)" %><br>
    <%= text_field_tag 'user[skill_list]', @user.skill_list.join(',') %>
  </div>
  <div class="field">
    <%= f.label :interest_list, "興味・関心(カンマ区切り)" %><br>
    <%= text_field_tag 'user[interest_list]', @user.interest_list.join(',') %>
  </div>
  <div class="actions">
    <%= f.submit %>
  </div>
<% end %>


UsersコントローラーのStrongParametersでこれらのパラメーターを受け取れるようにします。

# app/controllers/users_controller.rb
def user_params
  params.require(:user).permit(:name, :skill_list, :interest_list)
end


そして、入力したタグを画面に表示できるようにします。

<!-- app/views/users/index.html.erb -->
...
<table>
  <thead>
    <tr>
      <th>名前</th>
      <th>スキル・特技</th>
      <th>興味・関心</th>
      <th colspan="3"></th>
    </tr>
  </thead>

  <tbody>
    <% @users.each do |user| %>
      <tr>
        <td><%= user.name %></td>
        <td><%= render 'users/tag_list', tag_list: user.skill_list %></td>
        <td><%= render 'users/tag_list', tag_list: user.interest_list %></td>
        <td><%= link_to 'Show', user %></td>
        <td><%= link_to 'Edit', edit_user_path(user) %></td>
        <td><%= link_to 'Destroy', user, method: :delete, data: { confirm: 'Are you sure?' } %></td>
      </tr>
    <% end %>
  </tbody>
</table>
...


<!-- app/views/users_tag_list.html.erb -->
<% tag_list.each do |tag| %>
  <span class="label label-primary"><%= tag %></span>
<% end %>


では、タグが入力/表示できることを確認します。
まず、入力画面でカンマ区切りで入力します。
f:id:nipe880324:20150224140530j:plain:w480


そして保存して、一覧画面を表示すると入力したタグが表示されています。
f:id:nipe880324:20150224140540j:plain:w480




4. Bootstrap Tags Inputを使ってユーザーのタグ入力を簡易にする

Bootstrap Tags Inputは、タグ管理のためのjQueryプラグインです。
これを導入することで、タグの入力を次のように簡易にできるようにします。
tood image 3

http://timschlechter.github.io/bootstrap-tagsinput/examples/ の「Download」からソースファイルを取得します。

そして、jsファイルとcssファイルをRailsにコピーします。

cp ~/Downloads/bootstrap-tagsinput/bootstrap-tagsinput.min.js vendor/assets/javascripts/.
cp ~/Downloads/bootstrap-tagsinput/bootstrap-tagsinput.min.js.map vendor/assets/javascripts/.
cp ~/Downloads/bootstrap-tagsinput/bootstrap-tagsinput.css vendor/assets/stylesheets/.


application.jsapplication.cssに追加します。

// application.js
//= require bootstrap-tagsinput.min


// application.css
 *= require bootstrap-tagsinput


Tags Inputを使うのは簡単で、input要素にdata-role="tagsinput"を追加するだけです。

<!-- app/views/users/_form.html.erb -->
<%= form_for(@user) do |f| %>
  ...
  <div class="field">
    <%= f.label :skill_list, "スキル・特技" %><br>
    <%= text_field_tag 'user[skill_list]', @user.skill_list.join(','), "data-role" => "tagsinput" %>
  </div>
  <div class="field">
    <%= f.label :interest_list, "興味・関心" %><br>
    <%= text_field_tag 'user[interest_list]', @user.interest_list.join(','), "data-role" => "tagsinput" %>
  </div>
  ...
<% end %>


では、入力を確認してみます。タグの入力しやすくなり、同じタグは入力できなくなっています。
f:id:nipe880324:20150224140554j:plain:w480


カンマ区切りの文字列でサーバーに送られるので、問題なく登録ができます。
f:id:nipe880324:20150224140605j:plain:w480




次のように同じ「スキル・特技(skills_list)」や「興味・関心(interests_list)」を保持しているユーザーを表示できるようにしてみます。
f:id:nipe880324:20150224140517j:plain:w480


まず、ユーザ詳細画面を修正します。find_related_xxxxメソッドで関連しているユーザーを取得できます。

<!-- app/views/users/show.html.erb -->
<p id="notice"><%= notice %></p>

<p>
  <strong>Name:</strong>
  <%= @user.name %>
</p>

<p>
  <strong>スキル・特技:</strong>
  <%= render 'users/tag_list', tag_list: @user.skill_list %><br />
  <%= render 'users/related_users', users: @user.find_related_skills %>
</p>

<p>
  <strong>興味・関心:</strong>
  <%= render 'users/tag_list', tag_list: @user.interest_list %><br />
  <%= render 'users/related_users', users: @user.find_related_interests %>
</p>

<%= link_to 'Edit', edit_user_path(@user) %> |
<%= link_to 'Back', users_path %>


部分テンプレートを読んでいるので、作成します。

<!-- app/views/users/_related_users.html.erb -->
関連しているユーザー:
<%= users.map { |user| user.name }.join(" ") %>


画面を確認すると次のように表示されます。
f:id:nipe880324:20150224140517j:plain:w480


以上です。

他にもタグクラウドやタグでの検索などのトピックもあるので、詳細はActs As Taggable On - GitHub公式を参照してください。