1
0

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 1 year has passed since last update.

複数チェックボックス付き投稿・一覧表示・検索機能【RubyOnRails】

Last updated at Posted at 2022-11-30

目標

  • 投稿する際に事前に用意した選択肢からチェックボックスを生成、チェックをつけさせ、その情報をデータベースに保存する。
  • 投稿を一覧表示した際にチェックを付けた項目も見れるようにする。
  • 投稿する際に付けたチェックをもとに投稿を検索することができる。

環境

  • Ruby 3.0.4
  • Rails 6.1.7

前提

  • 投稿機能実装済み。
  • 今回は関係ないですが、User機能、いいね機能も実装済みなので、そこら辺の記述は読み飛ばしてください。

完成形

コントローラー(投稿を扱うもの:今回はtweet_controller.rb)
tweet_controller.rb
class TweetsController < ApplicationController
  before_action :authenticate_user!

  @@selections = ["てつや","しばゆー","ゆめまる","りょう","むしめがね","としみつ"]

#中略

  def index
      @tweets= Tweet.all
  end

  def search
    @selections = @@selections
    @tweets = []
    search_checkboxes = []

    for num in 0..@selections.length - 1 do
      search_checkboxes_index  = "search_checkbox_" + num.to_s
      if !params[search_checkboxes_index].nil?
        search_checkboxes.push(params[search_checkboxes_index])
      end
    end
    
    if params[:search_word] == ''and search_checkboxes == []
      @tweets= Tweet.all
    elsif params[:search_word] == nil and search_checkboxes == []
      @tweets= Tweet.all
    else
      tweets = Tweet.where("body LIKE ? ",'%' + params[:search_word] + '%')
      tweets.each do |d|
        union_checkbox = (d.checkboxes +  search_checkboxes).uniq
        if union_checkbox == d.checkboxes
          @tweets.push(d) 
        end
      end
    end

  end
  
  def new
    @tweet = Tweet.new
    @selections = @@selections
  end

  def create
    tweet = Tweet.new(tweet_params)
    tweet.user_id = current_user.id
    if tweet.save
      redirect_to :action => "index"
    else
      redirect_to :action => "new"
    end
  end

#中略

  private
  def tweet_params
    params.require(:tweet).permit(:body, :image,checkboxes:[])
  end

#後略
ルーティング
routes.rb
#前略
  get 'tweet/search' => 'tweets#search'
#後略
モデル
tweet.rb
#前略
    serialize :checkboxes, Array
#後略
ビューファイル
new.html.erb
<%= stylesheet_link_tag 'new', :media => "all" %>

<div class="post-container">
    <p class="title">投稿フォーム</p>
    <%= form_for(@tweet, :url => { controller:'tweets', action:'create'})do |f| %>
      <%= f.label :投稿内容 %><br>
      <%= f.text_field :body,size: 140%>

      <div class="field">
        <%= f.label :image %>
        <%= f.file_field :image %>
      </div>
      
      <div class="field">
        <% @selections.each_with_index do |checkboxes,i| %>
          <label>
            <%= check_box_tag 'tweet[checkboxes][]', checkboxes,false%>
            <%= checkboxes %>
          </label>
        <% end %>
      </div>

      <%= f.submit "送信"%><br>
    <% end %>
</div>

index.html.erb
<%= link_to "投稿を検索", tweet_search_path %> 

<div class="tweets-container">

<h3>Tweet一覧</h3>
  <% @tweets.each do |t| %>
    <div class="tweet">
      <div class="main-box">
        <div class="left-container">
          <%= t.user.email %>
          <a href="/users/<%= t.user.id %>"><%= t.user.name %></a>
          <%= t.body %>
          <%= image_tag t.image_url, size: "250x200" if t.image? %>
          <br>
          <%= t.checkboxes.join(' ')%>
        </div>

        <div class="right-container">
          <%= link_to "詳細", tweet_path(t.id) %>
          <% if user_signed_in? && current_user.id == t.user_id %>
           <%= link_to "編集する", edit_tweet_path(t.id) %>
           <%= link_to "削除する", tweet_path(t.id), method: :delete %>
         <% end %>
        </div>
      </div>
      <% if user_signed_in? %>
        <% if current_user.already_liked?(t) %>
            <%= link_to tweet_like_path(id: t.id, tweet_id: t.id), method: :delete do %>
              <i class="fas fa-heart"></i><%= t.likes.count %>
            <% end %>
        <% else %>
            <%= link_to tweet_likes_path(id: t.id, tweet_id: t.id), method: :post do %>
              <i class="far fa-heart"></i><%= t.likes.count %>
            <% end %>
        <% end %>
      <% else %>
          <p>いいねの数 = </p><%= t.likes.count %>
      <% end %>
        <p class="time"><%= t.created_at %></p>
    </div>
  <% end %>
</div>


search.html.erb
<h3>投稿を検索</h3>
  <%= form_tag({controller:"tweets",action:"search"}, method: :get) do %>
    <%= text_field_tag :search_word %>
    <div class="field">
      <% @selections.each_with_index do |item,i| %>
      <% pram = "search_checkbox_" + i.to_s %>
          <label>
            <%= check_box_tag pram, item, false%>
            <%= item %>
          </label>
        <% end %>
      </div>
    <%= submit_tag '検索する'  %>
<% end %>

<h3>検索結果</h3>
  <% @tweets.each do |t| %>
    <div class="tweet">
      <div class="main-box">
        <div class="left-container">
          <%= t.user.email %>
          <a href="/users/<%= t.user.id %>"><%= t.user.name %></a>
          <%= t.body %>
          <%= image_tag t.image_url, size: "250x200" if t.image? %>
          <br>
          <%= t.checkboxes.join(' ')%>
        </div>

        <div class="right-container">
          <%= link_to "詳細", tweet_path(t.id) %>
          <% if user_signed_in? && current_user.id == t.user_id %>
            <%= link_to "編集する", edit_tweet_path(t.id) %>
            <%= link_to "削除する", tweet_path(t.id), method: :delete %>
          <% end %>
        </div>
      </div>
      <% if user_signed_in? %>
        <% if current_user.already_liked?(t) %>
            <%= link_to tweet_like_path(id: t.id, tweet_id: t.id), method: :delete do %>
              <i class="fas fa-heart"></i><%= t.likes.count %>
            <% end %>
        <% else %>
            <%= link_to tweet_likes_path(id: t.id, tweet_id: t.id), method: :post do %>
              <i class="far fa-heart"></i><%= t.likes.count %>
            <% end %>
        <% end %>
      <% else %>
          <p>いいねの数 = </p><%= t.likes.count %>
      <% end %>
        <p class="time"><%= t.created_at %></p>
    </div>
  <% end %>
</div>

手順

1.カラムの追加

はじめに投稿のテーブル(今回はTweet)にカラムを追加します。名前は何でもいい(今回はcheckboxes)ですがデータ型はstringで用意してください。

rails generate migration AddCheckboxesToTweets checkboxes:string
rails db:migrate

カラムの追加に関してはこの記事を参考にしてみてください。
railsのデータベースで配列を保存するためにシリアライズします。

tweet.rb
#前略
    serialize :checkboxes, Array
#後略

2.checkbox付投稿の実装

check_box_tagを使ってチェックボックス機能を実装しました。複数あるのでeach_with_indexメソッドを使用しています。

new.html.erb
<div class="post-container">
    <p class="title">投稿フォーム</p>
    <%= form_for(@tweet, :url => { controller:'tweets', action:'create'})do |f| %>
      <%= f.label :投稿内容 %><br>
      <%= f.text_field :body,size: 140%>

      <div class="field">
        <%= f.label :image %>
        <%= f.file_field :image %>
      </div>
      
      <div class="field">
        <% @selections.each_with_index do |checkboxes,i| %>
          <label>
            <%= check_box_tag 'tweet[checkboxes][]', checkboxes,false%>
            <%= checkboxes %>
          </label>
        <% end %>
      </div>

      <%= f.submit "送信"%><br>
    <% end %>
</div>

選択肢に関しては、投稿ページや検索ページで複数回書くのは面倒なので、冒頭にクラス変数で定義して再利用できる形にしました。ストロングパラメーターは配列の場合書き方が違うので注意してください。

tweet_controller.rb
class TweetsController < ApplicationController
  before_action :authenticate_user!

  @@selections = ["てつや","しばゆー","ゆめまる","りょう","むしめがね","としみつ"]

#中略
  
  def new
    @tweet = Tweet.new
    @selections = @@selections
  end

  def create
    tweet = Tweet.new(tweet_params)
    tweet.user_id = current_user.id
    if tweet.save
      redirect_to :action => "index"
    else
      redirect_to :action => "new"
    end
  end

#中略

  private
  def tweet_params
    params.require(:tweet).permit(:body, :image,checkboxes:[])
  end

#後略

3.checkbox付一覧ページの実装

特に難しいことはしていません。each doを使ってcheckboxesの中身を表示しようとしましたが思ったようにいかなかったため、joinメソッドを用いて間に半角スペースを入れた結合文字列にして表示しています。

index.html.erb
<%= link_to "投稿を検索", tweet_search_path %> 

<div class="tweets-container">

<h3>Tweet一覧</h3>
  <% @tweets.each do |t| %>
    <div class="tweet">
      <div class="main-box">
        <div class="left-container">
          <%= t.user.email %>
          <a href="/users/<%= t.user.id %>"><%= t.user.name %></a>
          <%= t.body %>
          <%= image_tag t.image_url, size: "250x200" if t.image? %>
          <br>
          <%= t.checkboxes.join(' ')%>
        </div>

        <div class="right-container">
          <%= link_to "詳細", tweet_path(t.id) %>
          <% if user_signed_in? && current_user.id == t.user_id %>
           <%= link_to "編集する", edit_tweet_path(t.id) %>
           <%= link_to "削除する", tweet_path(t.id), method: :delete %>
         <% end %>
        </div>
      </div>
      <% if user_signed_in? %>
        <% if current_user.already_liked?(t) %>
            <%= link_to tweet_like_path(id: t.id, tweet_id: t.id), method: :delete do %>
              <i class="fas fa-heart"></i><%= t.likes.count %>
            <% end %>
        <% else %>
            <%= link_to tweet_likes_path(id: t.id, tweet_id: t.id), method: :post do %>
              <i class="far fa-heart"></i><%= t.likes.count %>
            <% end %>
        <% end %>
      <% else %>
          <p>いいねの数 = </p><%= t.likes.count %>
      <% end %>
        <p class="time"><%= t.created_at %></p>
    </div>
  <% end %>
</div>


tweet_controller.rb

#ここから追記

  def index
      @tweets= Tweet.all
  end

#ここまで追記

4.checkbox付検索ページの実装

ここが今回の山場です。
今回は検索ページと検索結果ページを同じにしているので、<%= form_tag({controller:"tweets",action:"search"}, method: :get) do %>として、ビューファイルからTweetsコントローラーのsearchアクションにgetを飛ばしています。
まずはbodyカラム(主な内容を記述するカラム)であいまい検索をかけ、変数tweetsに入れます。そしてtweetを対象にeach doを行い、checkboxの検索条件を満たしたものをインスタンス変数として用意しておいた配列@tweetsに格納していきます。

tweet_controller.rb

#ここから追記

  def search
    @selections = @@selections
    @tweets = []
    search_checkboxes = []

    for num in 0..@selections.length - 1 do
      search_checkboxes_index  = "search_checkbox_" + num.to_s
      if !params[search_checkboxes_index].nil?
        search_checkboxes.push(params[search_checkboxes_index])
      end
    end
    
    if params[:search_word] == ''and search_checkboxes == []
      @tweets= Tweet.all
    elsif params[:search_word] == nil and search_checkboxes == []
      @tweets= Tweet.all
    else
      tweets = Tweet.where("body LIKE ? ",'%' + params[:search_word] + '%')
      tweets.each do |d|
        union_checkbox = (d.checkboxes +  search_checkboxes).uniq
        if union_checkbox == d.checkboxes
          @tweets.push(d) 
        end
      end
    end

  end

#ここまで追記

search.html.erb
<h3>投稿を検索</h3>
  <%= form_tag({controller:"tweets",action:"search"}, method: :get) do %>
    <%= text_field_tag :search_word %>
    <div class="field">
      <% @selections.each_with_index do |item,i| %>
      <% pram = "search_checkbox_" + i.to_s %>
          <label>
            <%= check_box_tag pram, item, false%>
            <%= item %>
          </label>
        <% end %>
      </div>
    <%= submit_tag '検索する'  %>
<% end %>

<h3>検索結果</h3>
  <% @tweets.each do |t| %>
    <div class="tweet">
      <div class="main-box">
        <div class="left-container">
          <%= t.user.email %>
          <a href="/users/<%= t.user.id %>"><%= t.user.name %></a>
          <%= t.body %>
          <%= image_tag t.image_url, size: "250x200" if t.image? %>
          <br>
          <%= t.checkboxes.join(' ')%>
        </div>

        <div class="right-container">
          <%= link_to "詳細", tweet_path(t.id) %>
          <% if user_signed_in? && current_user.id == t.user_id %>
            <%= link_to "編集する", edit_tweet_path(t.id) %>
            <%= link_to "削除する", tweet_path(t.id), method: :delete %>
          <% end %>
        </div>
      </div>
      <% if user_signed_in? %>
        <% if current_user.already_liked?(t) %>
            <%= link_to tweet_like_path(id: t.id, tweet_id: t.id), method: :delete do %>
              <i class="fas fa-heart"></i><%= t.likes.count %>
            <% end %>
        <% else %>
            <%= link_to tweet_likes_path(id: t.id, tweet_id: t.id), method: :post do %>
              <i class="far fa-heart"></i><%= t.likes.count %>
            <% end %>
        <% end %>
      <% else %>
          <p>いいねの数 = </p><%= t.likes.count %>
      <% end %>
        <p class="time"><%= t.created_at %></p>
    </div>
  <% end %>
</div>
routes.rb
#前略
  get 'tweet/search' => 'tweets#search'
#後略
1
0
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
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?