1
1

More than 3 years have passed since last update.

[Rails]中間テーブルを用いたタグ付け機能の実装(Gemなし)

Last updated at Posted at 2020-12-21

目標

チェックボックスを複数選択し、中間テーブルを介してタグ付け機能を実装する。

開発環境

・Ruby: 2.5.7
・Rails: 5.2.4
・Vagrant: 2.2.7
・VirtualBox: 6.1
・OS: macOS Catalina

E-R図

スクリーンショット 2020-12-21 10 58 14
上記の画像は今回の実装するイメージです。
今回は私が実装したサウナの種類を複数選択して登録する例で話させていただきます。

事前準備

画像のようなサウナを新規作成する画面を用意しました。
今回の話で使用するのは、サウナジャンルの複数のチェックボックスを選択して中間テーブルであるサウナジャンルを用いて実装する方法です。
登録機能など基本的な機能は実装済みの前提でお話させていただきます。
スクリーンショット 2020-12-21 11 07 41

モデルにアソシエーションを記述する

app/models/sauna.rb
class Sauna < ApplicationRecord
  has_many :sauna_genres, dependent: :destroy
  has_many :genres, through: :sauna_genres
end
app/models/sauna_genre.rb
class SaunaGenre < ApplicationRecord
  belongs_to :genre
  belongs_to :sauna
end
app/models/genre.rb
class Genre < ApplicationRecord
  has_many :sauna_genres
  has_many :saunas, through: :sauna_genres
end

controller

app/controllers/saunas_controller.rb
  def create
    @sauna = Sauna.new(sauna_params)
    @sauna.user_id = current_user.id
    if @sauna.save
      redirect_to user_sauna_path(@sauna)
    else
      render 'new'
    end
  end

 #省略

   def sauna_params
    params.require(:sauna).permit(
      :name,
      genre_ids: []
    )
  end

genre_ids: []は複数チェックボックスの値を配列で渡すことを許可しています。

html.erb
<div>
  <%=f.label :genre_ids, "ジャンル機能" %>
  <span>
    <% Genre.all.each do |genre| %>
      <%= f.check_box :genre_ids, 
         { multiple: true, checked: @sauna.genres.find_by(id: genre.id).present?, 
         include_hidden: false }, genre[:id] %>
       <label class="form-check-label">
         <%= genre.name %>
       </label>
     <% end %>
  </span>
</div>

form.check_box :label_ids→ paramsの値として、"label_ids"=>["1", "2", "3"]このような形でハッシュのキーを持つ値を送れます。
multipleオプションを使用することで、複数のチェックボックスのパラメータを配列形式で送れます。
checked: @task.labels.find_by(id: label.id).present?これは編集画面等で登録されているラベルにチェックを付けるということをしています。
include_hidden: false→登録のない項目については、パラメータを送らないメソッドです。

このまま実装すると一見複数中間テーブルも作成できるし、編集の時もしっかりチェックついてるし問題ないと思っていたのですが、編集画面でチェックを全て外して更新してもジャンルの複数の名前は消えなかったのです。
何が原因か、、、この実装方法だと、空で送ってしまうと値としてnilが返ってきてしまいます。
それを解決するためにストロングパラメーターを少し工夫します。

app/controllers/saunas_controller.rb
#省略

  def sauna_params
    values = params.require(:sauna).permit(
      :name,
      genre_ids: []
    )
    if values[:genre_ids].nil?
      values[:genre_ids] = [] 
    end
    return values
  end

このようにすることでgenre_idsにもしnilが返ってきた時に空の配列を送ることでジャンルを持たないものも作成することができました。
ジャンルを作っている以上、ジャンルなしということはないとは思いますが、気づいたので備忘録として残しておきます。

ありがとうございました

1
1
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
1
1