■ 環境
- windows 8.1
- Rails 5.1.6
- ruby 2.3.3p222 (2016-11-21 revision 56859) [i386-mingw32]
#1. 簡単な導入テスト
$ rails _5.1.6_ new hoge
source 'https://rubygems.org'
gem 'rails', '5.1.6'
gem 'puma', '3.9.1'
gem 'sass-rails', '5.0.6'
gem 'uglifier', '3.2.0'
gem 'coffee-rails', '4.2.2'
gem 'jquery-rails', '4.3.1'
gem 'turbolinks', '5.0.1'
gem 'jbuilder', '2.7.0'
gem 'acts-as-taggable-on', '~> 6.0' #追加
group :development, :test do
gem 'sqlite3', '1.3.13'
gem 'byebug', '9.0.6', platform: :mri
end
group :development do
gem 'web-console', '3.5.1'
gem 'listen', '3.1.5'
gem 'spring', '2.0.2'
gem 'spring-watcher-listen', '2.0.1'
end
group :test do
gem 'rails-controller-testing', '1.0.2'
gem 'minitest', '5.10.3'
gem 'minitest-reporters', '1.1.14'
gem 'guard', '2.13.0'
gem 'guard-minitest', '2.4.4'
end
group :production do
gem 'pg', '0.20.0'
end
# Windows環境ではtzinfo-dataというgemを含める必要があります
gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
$ bundle update
$ bundle install
$ rails generate scaffold user name:string
$ rails acts_as_taggable_on_engine:install:migrations
$ rails db:migrate
$ rails db:migrate RAILS_ENV=test
get 'tags/:tag', to: 'users#index', as: :tag #追加
acts_as_taggable #使用するmodelに追加
#user_paramsを書き換え
def user_params
params.require(:user).permit(:name, :tag_list)
end
#indexアクション書き換え
def index
if params[:tag]
@users = User.tagged_with(params[:tag])
else
@users = User.all
end
end
<% @users.each do |user| %>
<tr>
<td><%= user.name %></td>
<td><%= raw(user.tag_list.map { |t| link_to t, tag_path(t) }.join(', ')) %></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 %>
<div class="field">
<%= form.label :name %>
<%= form.text_field :name, id: :user_name %>
<%= form.label :tag_list %> <!--追加-->
<%= form.text_field :tag_list, id: :user_name %> <!--追加-->
</div>
<p>tags: <%= raw(@user.tag_list.map { |t| link_to t, tag_path(t) }.join(', ')) %></p> <!--追加-->
##参照
https://qiita.com/mishikunxo/items/537eea201542b9ee3fa7
#2.導入
実装イメージ
$ rails _5.1.6_ new hoge
source 'https://rubygems.org'
gem 'rails', '5.1.6'
gem 'puma', '3.9.1'
gem 'sass-rails', '5.0.6'
gem 'uglifier', '3.2.0'
gem 'coffee-rails', '4.2.2'
gem 'jquery-rails', '4.3.1'
gem 'turbolinks', '5.0.1'
gem 'jbuilder', '2.7.0'
gem 'acts-as-taggable-on', '~> 6.0' #追加
group :development, :test do
gem 'sqlite3', '1.3.13'
gem 'byebug', '9.0.6', platform: :mri
end
group :development do
gem 'web-console', '3.5.1'
gem 'listen', '3.1.5'
gem 'spring', '2.0.2'
gem 'spring-watcher-listen', '2.0.1'
end
group :test do
gem 'rails-controller-testing', '1.0.2'
gem 'minitest', '5.10.3'
gem 'minitest-reporters', '1.1.14'
gem 'guard', '2.13.0'
gem 'guard-minitest', '2.4.4'
end
group :production do
gem 'pg', '0.20.0'
end
# Windows環境ではtzinfo-dataというgemを含める必要があります
gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
$ bundle update
$ bundle install
$ rails generate controller Users index search
$ rails generate model User name:string
$ rails acts_as_taggable_on_engine:install:migrations
$ rails db:migrate
$ rails db:migrate RAILS_ENV=test
array = %w(aaa bbb ccc ddd eee fff ggg)
array.each{ |tag|
tag_list = ActsAsTaggableOn::Tag.new
tag_list.name = tag
tag_list.save
}
#-------------------------------------------------------------------------------
# Userに紐づいていないタグ(aaa, bbb, ... ggg)を事前に入れておく
#-------------------------------------------------------------------------------
$ rails db:seed
Rails.application.routes.draw do
root 'users#index'
get 'users/index', to: 'users#index'
post 'users/create', to: 'users#create'
get 'users/search', to: 'users#search'
post 'users/search', to: 'users#search'
get 'tags/:tag', to: 'users#index', as: :tag
end
class UsersController < ApplicationController
def index
if params[:tag]
@users = User.tagged_with(params[:tag])
else
@users = User.all
end
@new_user = User.new
@tags = ActsAsTaggableOn::Tag.all
#-------------------------------------------------------------------------------
# もともと @tags = User.all としていたが、これだとUserに紐づいて登録されているタグのみ表示される
# Userと紐づいていないタグを参照する場合 @tags = ActsAsTaggableOn::Tag.all としておくとうまくいった
#-------------------------------------------------------------------------------
end
def create
@user = User.new(user_params)
@user.save
redirect_to users_index_path
end
def search
@users = User.where("name LIKE ?", "%#{user_params[:name]}%")
@users = @users.tagged_with(user_params[:tag_list], :match_all => false)
end
#-------------------------------------------------------------------------------
# 「:match_all => false」←これにかなりてこずりました。
# やりたい事は以下のようなフィルタリングです。
# ↓ 登録データ
# yamadaさん タグaaa,タグbbb,タグccc
# yamahaさん タグaaa,タグbbb
# yamamotoさん タグaaa,タグccc
# tanakaさん タグaaa,タグbbb
#
# ↓ 名前yama でフィルタリング(名前にyamaを持つ)
# yamadaさん タグaaa,タグbbb,タグccc
# yamahaさん タグaaa,タグbbb
# yamamotoさん タグaaa,タグccc
#
# ↓ タグaaa,タグbbbでフィルタリング(タグaaaとタグbbbの両方を持つ)
# yamadaさん タグaaa,タグbbb,タグccc
# yamahaさん タグaaa,タグbbb
# @users = User.where("name LIKE ?", "%#{user_params[:name]}%")これは見たままの意味です。
# 問題なのは「:match_all => false」これです。
# サイトで探した限り「:match_all => true」の事しかありませんでした。
# 「:match_all => true」では完全一致したものしか取りだしません。
# 上の例で言えばyamadaさんはタグcccが余計にあるため除外されます。
#-------------------------------------------------------------------------------
private
def user_params
params.require(:user).permit(:name, tag_list: [])
#-------------------------------------------------------------------------------
# "tag_list: []" はviewのform_for内のcheckboxがpostする値が配列になっているため、
# 1.簡単な導入テストの ":tag_list" から "tag_list: []" に変更した。
#
# :tag_list は "aaa,bbb,ccc" の文字列を扱う
# tag_list: [] は ["aaa","bbb","ccc"] の配列を扱う
#-------------------------------------------------------------------------------
end
end
class User < ApplicationRecord
acts_as_taggable
end
<table>
<tbody>
<% @users.each do |user| %>
<tr>
<td><%= user.name %></td>
<td><%= raw(user.tag_list.map { |t| link_to t, tag_path(t) }.join(' ')) %></td>
</tr>
<% end %>
</tbody>
</table>
<%= form_for(@new_user, url: {controller: 'users', action: 'create' }) do |f| %>
<%= f.label :name %>
<%= f.text_field :name %>
<% @tags.each do |tag| %>
<%= f.check_box :tag_list, { multiple: true }, "#{tag.name}", nil %>
<%= f.label " #{tag.name}(#{tag.taggings_count})" %>
<!-- ------------------------------------------------------------------
"#{tag.name}" これだとタグ名が Aaaとなる(一文字目が大文字になる)
" #{tag.name}" これだと(スペース入れる)タグ名は "aaa"となる
----------------------------------------------------------------------- -->
<% end %>
<%= f.submit "作成" %>
<% end %>
<%= form_for(@new_user, url: {controller: 'users', action: 'search' }) do |f| %>
<%= f.label :name %>
<%= f.text_field :name %>
<% @tags.each do |tag| %>
<%= f.check_box :tag_list, { multiple: true }, "#{tag.name}", nil %>
<%= f.label " #{tag.name}(#{tag.taggings_count})" %>
<% end %>
<%= f.submit "検索" %>
<% end %>
<table>
<tbody>
<% @users.each do |user| %>
<tr>
<td><%= user.name %></td>
<td><%= raw(user.tag_list.map { |t| link_to t, tag_path(t) }.join(' ')) %></td>
</tr>
<% end %>
</tbody>
</table>
##参照
https://github.com/mbleigh/acts-as-taggable-on
https://higelog.brassworks.jp/93
https://qiita.com/takeyuweb/items/3e313a7842997ba15345
https://stackoverflow.com/questions/6697540/acts-as-taggable-on-and-checkbox-tags
https://qiita.com/tomomomo1217/items/5c3c0ff92eff36e85b20
#3.補足 check_boxのlabelをクリックしてチェックを入れる
railsで自動生成されたhtmlコードを確認する
<%= f.check_box :tag_list, { multiple: true }, "#{tag.name}", nil %>
<%= f.label " #{tag.name}(#{tag.taggings_count})" %>
<input type="checkbox" value="aaa" name="group[tag_list][]" id="user_tag_list_aaa" />
<label for="user_ aaa(1)"> aaa(1)</label>
htmlコードのcheckbox のid="user_tag_list_aaa"
とlabelのlabel for="user_ aaa(1)"
が一致していない場合、labelをクリックしてもチェックボックスは無反応になる。そのため以下のようにrailsのコードを変えると良い。
<%= f.check_box :tag_list, { multiple: true }, tag.name, nil %>
<%= f.label "tag_list_#{tag.name}", "#{tag.name}(#{tag.taggings_count})" %>
tag_list_#{tag.name}
は強引できれいではないですが、これでうまくいきます。
<input type="checkbox" value="aaa" name="user[tag_list][]" id="user_tag_list_aaa" />
<label for="user_tag_list_aaa"> aaa(1)</label>
#4.補足 check_boxのlabelをクリックしてチェックを入れる(idとvalueに違う値を入れる)
check_boxの
value = tag.name
id = tag.id
のような形でかつ、
labelをクリックしてチェックが可能
にしたい。
<%= f.check_box :tag_list, { multiple: true, id: "user_tag_list_#{tag.id}" }, tag.name, nil %>
<%= f.label "tag_list_#{tag.id}", "#{tag.name}(#{tag.taggings_count})" %>
<input type="checkbox" value="aaa" name="user[tag_list][]" id="user_tag_list_1" />
<label for="user_tag_list_1">aaa(1)</label>