#はじめに
railsでアプリを作っていて、投稿をタグ機能で整理したい!
タグ検索機能を実装して、ジャンルごとに投稿し、ジャンルごとに投稿を見たい!
ということはありませんか?
ぜひ作っちゃいましょう!
これで、「伝記」を押すと、伝記タグのついた投稿だけ出てきます!
#モデル
今回は、本の紹介サイトで、本をジャンル分けで表示するサイトを作成します。
作るモデルは以下の3つ!
Bookモデル以外は一緒に作っていきましょう!
Book | Book_tag | Tag |
---|---|---|
id | id | id |
title | book_id | name |
text | tag_id |
テーブル
・books
投稿テーブル
・tags
タグに関するテーブル
・book_tags
投稿とタグを紐づけるための中間テーブル
#1.事前準備
この記事はbooksテーブル(投稿機能)は作成済みの前提なので注意してください。
下記のコントローラーでは投稿、削除だけ書いてます。詳細、編集はお好みで!
・booksコントローラー
・Bookモデル
・booksテーブル( id, title:string, body:text )
・app>views>books>indexとnewページ
↓ booksコントローラー
class BooksController < ApplicationController
def index
@books = Book.all
end
def new
@book = Book.new
end
def create
book = Book.new(book_params)
if book.save
redirect_to :action => "index"
else
redirect_to :action => "new"
end
end
def destroy
book = Book.find(params[:id])
book.destroy
redirect_to action: :index
end
private
def book_params
params.require(:book).permit(:title, :body)
end
end
↓ app>views>books>index/new↓
<h1>本を探そう</h1>
<%= link_to "新規投稿へ", new_book_path %>
<div class="books-container">
<% @books.each do |b| %>
<div class="book">
<%= b.title %>
<%= b.body %>
</div>
<%= link_to "削除する", book_path(b.id), method: :delete %>
<% end %>
</div>
<h1>新規投稿</h1>
<%= form_for @book do |b| %>
<div class="field">
<%= f.label :title %>
<%= f.text_field :title, :size => 140 %>
</div>
<div class="field">
<%= f.label :body %>
<%= f.text_field :body, :size => 140 %>
</div>
<%= f.submit "保存する" %>
<% end %>
<%= link_to "本一覧に戻る", books_path %>
↓ config>routes.rb
Rails.application.routes.draw do
resources :books
end
#2.モデル作成
次に、Tagモデルを作成しましょう!
rails generate model Tag name:string
続いてBookモデルとTagモデルの中間テーブルとなるBook_tagモデルを作成して行きます。
中間テーブルの作成にはreferencesというパラメーターを用いてBookモデル及びTagモデルの中間テーブルであることを示し、rails db:migrate
でDBに反映させます。
rails generate model Book_tag book:references tag:references
rails db:migrate
#3.モデルのアソシエーション設定
class BookTag < ApplicationRecord
belongs_to :tag
belongs_to :book
end
上記はrails generate model Book_tag book:references tag:references
により既に記載されてるはず!
class Book < ApplicationRecord
has_many :book_tags, dependent: :destroy
has_many :tags, through: :book_tags, dependent: :destroy
end
has_many :book_tags, dependent: :destroy
has_many :books, through: :book_tags, dependent: :destroy
#4.seed.rbにタグレコード追加
##省略
Tag.create([
{ name: '小説' },
{ name: '漫画' },
{ name: '伝記'},
{ name: '実用書'},
{ name: '教育書'},
])
ここで、DBに変更を反映します。
rails db:seed
#5.viewのformでtagを選択できるようにする
#省略
#追記ここから
<div class="check_box">
<%= form.collection_check_boxes(:tag_ids, Tag.all, :id, :name) do |tag| %>
<div class='form-check'>
<%= tag.label do %>
<%= tag.check_box %>
<%= tag.text %>
<% end %>
</div>
<% end %>
</div>
#追記ここまで
<%= f.submit "保存する" %>
<% end %>
#6.コントローラーでストロングパラメーターを追記
#省略
def book_params
params.require(:book).permit(:title, :body, tag_ids: [])
end
end
#7 .投稿にtagが表示されるようviewを追記
渡された複数のタグをeach文で表示させるためそれぞれshowとindexに以下を追記。
<% @book.tags.each do |tag| %>
<%= tag.name %>
<% end %>
<% @books.each do |b| %>
<div class="book">
<%= b.title %>
<%= b.body %>
#ここから追記
<% b.tags.each do |tag| %>
<%= tag.name %>
<% end %>
#ここまで
</div>
<% end %>
#8 .タグ検索機能の実装
最後にここからタグ検索機能を実装して行きます
選択したtagの投稿のみ取得するようにindex.html.erbを以下のように編集して行きます。
<h1>本を探そう</h1>
<%= link_to "新規投稿へ", new_book_path %>
#ここから追記
<%= form_tag books_path, method: :get, class: 'boards__searchForm' do %>
<% @tags.each do |tag| %>
<div class="tag-box">
<%= link_to tag.name, books_path(name: tag.id) %>
</div>
<% end %>
<div class="tag-box">
<%= link_to "全ての本", books_path %>
</div>
#ここまで
<div class="books-container">
<% @books.each do |b| %>
<div class="book">
<%= b.title %>
<%= b.body %>
<% book.tags.each do |tag| %>
<%= tag.name %>
<% end %>
</div>
<% end %>
</div>
#ここから追記(これ忘れずに!)
<% end %>
#ここまで
続いてposts_controllerのindexアクションを以下のように編集します。
class BooksController < ApplicationController
def index
#ここから追記
@tags = Tag.all
@books = params[:name].present? ? Tag.find(params[:name]).books : Book.all
#ここまで
end
Tag.find(params[:name]).books : Book.all
で、nameがセットされていたらTagから関連づけられたbooksを呼び、nameの指定がなければ、全ての投稿を表示するよう記述されています。
#9 .SCSS
ここは好みですが、リンクを箱で囲う感じにして、
.tag-box{
background-color: aquamarine;
display: inline;
border: 1px solid #000000;
a{
text-decoration: none;
}
}
## かんせーい
(あ、詳細へ、編集する、は今回触れてないのでここは無視してください。
あと教育書の右に「すべての本」というのもついてるはず!)
##終わりに
大学生限定プログラミングコミュニティのGeekSalonでメンターをしてます!
大学生でプログラミング気になる人はぜひHP見てみてね
要チェック!大学生限定プログラミングコミュニティGeekSalon
参考サイト: railsでタグ検索機能を実装し多対多を理解する