5
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Railsでタグ機能を使い、ジャンルで絞れる検索機能を作成

Last updated at Posted at 2021-02-04

#はじめに
railsでアプリを作っていて、投稿をタグ機能で整理したい!
タグ検索機能を実装して、ジャンルごとに投稿し、ジャンルごとに投稿を見たい!
ということはありませんか?
ぜひ作っちゃいましょう:tiger:

###:sparkles: 完成図 :sparkles:
完成図1 (200).png

これで、「伝記」を押すと、伝記タグのついた投稿だけ出てきます!
完成図2 (201).png

#モデル
今回は、本の紹介サイトで、本をジャンル分けで表示するサイトを作成します。
作るモデルは以下の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コントローラー

books_controller.rb
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↓

books/index.html.erb
<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>
books/new.html.erb
<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

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.モデルのアソシエーション設定

book_tag.rb
class BookTag < ApplicationRecord
 belongs_to :tag
 belongs_to :book
end

上記はrails generate model Book_tag book:references tag:referencesにより既に記載されてるはず!

book.rb
class Book < ApplicationRecord
 has_many :book_tags, dependent: :destroy
 has_many :tags, through: :book_tags, dependent: :destroy
end
tag.rb
  has_many :book_tags, dependent: :destroy
  has_many :books, through: :book_tags, dependent: :destroy

#4.seed.rbにタグレコード追加

db/seeds.rb
##省略
Tag.create([
    { name: '小説' },
    { name: '漫画' },
    { name: '伝記'},
    { name: '実用書'},
    { name: '教育書'},
    ])

ここで、DBに変更を反映します。

ターミナル
rails db:seed

#5.viewのformでtagを選択できるようにする

books/new.html.erb
#省略
#追記ここから
<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.コントローラーでストロングパラメーターを追記

books/books_controller.rb
#省略
    def book_params
      params.require(:book).permit(:title, :body, tag_ids: [])
    end
end

#7 .投稿にtagが表示されるようviewを追記
渡された複数のタグをeach文で表示させるためそれぞれshowとindexに以下を追記。

books/show.html.erb
<% @book.tags.each do |tag| %>
    <%= tag.name %>
<% end %>
books/index.html.erb
<% @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を以下のように編集して行きます。

books/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アクションを以下のように編集します。

books_controller.rb
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
ここは好みですが、リンクを箱で囲う感じにして、

application.scssかbooks.scss
.tag-box{
    background-color: aquamarine;
    display: inline;
    border: 1px solid #000000;

    a{
        text-decoration: none;
    }
}

##:sparkles: かんせーい :sparkles:
完成図2 (201).png
(あ、詳細へ、編集する、は今回触れてないのでここは無視してください。
あと教育書の右に「すべての本」というのもついてるはず!)

##終わりに
大学生限定プログラミングコミュニティのGeekSalonでメンターをしてます!
大学生でプログラミング気になる人はぜひHP見てみてね:yellow_heart:
要チェック!大学生限定プログラミングコミュニティGeekSalon

参考サイト: railsでタグ検索機能を実装し多対多を理解する

5
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?