たけのこブログ

凡人が頑張って背伸びするブログ

チェックボックス機能を実装

どうもこんにちは、たけのこです。今日はとても暑いです...汗 Railsは学び始めて半年経ってないくらいですが、学んできたこと、最近実装したものを少しずつ記事にできれば良いなと思って始めました。

ここでは、プログラムを書いたときに、そのプログラムがどんな種類なのかタグをつけるという例でチェックボックス機能を実装していきたいと思います

完成形

f:id:YuKR:20190613155653p:plain  

ER図の関係とモデル部分の実装

まず、プログラムの内容に関連したcodesテーブル、タグの種類が格納されているtagsテーブルがあり、その中間テーブルにcodes_tagsテーブルがある多対多の関係を想定して進めていきます。さらに、ユーザのテーブルであるusersテーブルとcodesテーブルは1対多の関係が成立しているものとして話を進めています。 また、選べるタグの内容は決まっているものとします。これは、ユーザが好きにタグを設定しても良いことにしてしまうと、爆発的にデータ数が増えてしまうため、RDBMSでは対処できないからです(NoSQLとかが必要になってくると思います)

  tag.rb

class Tag < ApplicationRecord
  validates :name, presence: true, length: { maximum: 20 }
  has_many :code_tags
  has_many :codes, through: :code_tags, source: :code
end

code.rb

class Code < ApplicationRecord
  has_many :code_tags
  has_many :tags, through: :code_tags, source: :tag
end

code_tag.rb

class CodeTag < ApplicationRecord
  belongs_to :code
  belongs_to :tag
end

コントローラ部分の実装

newアクションでは、コードの空のインスタンスを生成し、タグの内容を全て呼び出しています。 createアクションでは、実際に完成形として見せたビューに内容を入力したときの内容となっています。

codes_controller.rb

class CodesController < ApplicationController
  
  def new
    @code = User.codes.build
    @tags = Tag.all
  end

  def create
    @code = current_user.codes.build(code_params)

    if @code.save
      flash[:success] = 'コードを公開しました。'
      redirect_to root_url
    else
      #今までのユーザのプログラムの投稿内容に関するインスタンスを生成してトップページに表示させている
      @codes = User.codes.order('created_at DESC').page(params[:page])
      flash[:danger] = 'コードの公開に失敗しました。'
      render 'toppages/index'
    end
  end

  private
  
  def code_params
    params.require(:code).permit(:content, :summary, :program, :data, {tag_ids: []})
  end

ここで重要なのは、codesのコントローラファイルにおけるストロングパラメータで以下を記載することが重要です。

def code_params
    params.require(:code).permit(:content, :summary, :program, :data, {tag_ids: []})
end

これによって、タグの配列のパラメータを許可しており、複数のチェックボックスに入力しても処理を可能にしています。

ビュー部分の実装

codesフォルダの中のnew.html.erbのコード内容

<div class="text-center">
  <h1>コードを公開する</h1>
</div>

<div class="row">
  <div class="col-md-6 col-md-offset-3">
    <%=form_for(@code) do |f| %>
      <%= render 'layouts/error_messages', model: f.object %>
      
      <div class="form-group">
        <%= f.label :program, 'プログラム' %>
        <%= f.text_area :program, class: 'form-control', placeholder: 'Markdown形式での入力(```の間にプログラムを納入する形式)', rows: 15 %>
      </div>
      
      <div class="form-group">
        <%= f.label :data, 'データ' %>
        <%= f.file_field :data %>
      </div>
      
      <div class="form-group">
        <%= f.label :tags, class: 'control-label' %>
          <div class="checkbox">
            <%= collection_check_boxes(:code, :tag_ids, Tag.all, :id, :name) do |b| %>
              <%= b.label { b.check_box + b.text } %>
            <% end %>
          </div>
      </div>
      
      <%= f.submit '公開する', class: 'btn btn-primary btn-block' %>
    <% end %>
  </div>
</div>

ここで、以下のようにチェックボックスを作成しています。

<div class="form-group">
  <%= f.label :tags, class: 'control-label' %>
    <div class="checkbox">
      <%= collection_check_boxes(:code, :tag_ids, Tag.all, :id, :name) do |b| %>
        <%= b.label { b.check_box + b.text } %>
      <% end %>
    </div>
</div>

<%= collection_check_boxes(:code, :tag_ids, Tag.all, :id, :name) do |b| %>は多対多の関係を前提としたビューヘルパーで、引数の説明は以下のようになっています

  • 第一引数(:code)...オブジェクト

  • 第二引数(:tag_ids)...チェックされたTagのidを処理するのに必要(code_tagのtag_id)

  • 第三引数(Tag.all)...inputタグの元となるオブジェクト配列

  • 第四引数(:id)...作成されたinputタグのvalueとなる値を指定。ここでは、各tagのidが入力されます

  • 第五引数(:name)...作成されたinputタグのテキストを指定。ここでは、各tagのnameが入力されます

つまり、Tagを取得して、code[tag_ids][]とし、valueにtag_id,テキストにtag.nameを使用しています。

タグの名前の生成

最後に、完成形にあるようにタグの名前を生成するため、 db/seeds.rbで記載します。

Tag.create(name: '機械学習')
Tag.create(name: '最適化')
Tag.create(name: 'スクレイピング')
Tag.create(name: 'データ分析')
Tag.create(name: 'アプリ開発')
Tag.create(name: 'API')
Tag.create(name: 'ライブラリ・パッケージ')
Tag.create(name: 'ディープラーニング')
Tag.create(name: 'デバッグ')
Tag.create(name: 'セキュリティ')

上記を書いたら、rails db:seedを実行すれば、無事にタグの名前(チェック項目)が記録されます。もしもherokuでもデプロイする場合には、heroku run rals db:seed と実行すれば問題ありません。

まとめ

今回は、Railsチェックボックス機能を実装する手順を説明しました。チェックボックスはアンケートでも頻繁に使用されると思うので、覚えておいて損はないと思いました。