activerecord-importを使った一括登録について

#はじめに
Qiita初投稿です。

アプリ作る際に一括でデータの登録をしたくて、activerecord-importのgemを導入して使ってみたので、その使い方について書いてみようと思います。間違い等あればご指摘いただけるとありがたいです。

**bulk_insertはRails6では標準サポートされているようです。**

# 開発環境
- Ruby2.5.1
- Rails5.2.4.2
- Haml
- Sass

# 今回実装した機能の概要
CRM（顧客管理）を作ってます。一斉DMを送るなど、複数の顧客に対して一括のデータを登録します。
![ab73ba83eed44a1b04abeb7f083b020d.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/423589/0f24d489-037e-4f20-6e3c-dce80a46bfa4.gif)

# モデル
client(顧客)モデルとcontact（顧客に対してのコンタクト）モデルがあり、ネスティングさせています。

```ruby:client.rb
 has_many :contacts
```
```ruby:contact.rb
 belongs_to :client
```

# コントローラー(該当部分のみ抜粋)
一括登録のためのbulk_insertアクションを作成しました。client_idを配列で取っています。1つずつ配列に入れて、importします。

```ruby:clients_controller.rb
  def bulk_insert
    contact_array=[]
    bulk_params[:client_ids].each do |cid|
      contact=Contact.new(act_cat_id: bulk_params[:act_cat_id],detail: bulk_params[:detail],start_date: bulk_params[:start_date],end_date: bulk_params[:end_date],in_progress: bulk_params[:in_progress],client_id: cid)
      contact_array << contact
    end
    Contact.import contact_array
    redirect_to clients_path
  end

  private
  def bulk_params
    params.require(:contact).permit(:act_cat_id,:detail,:start_date,:end_date,:in_progress,{:client_ids => []})
  end

```

# ルーティング


```ruby:routes.rb
Rails.application.routes.draw do
  devise_for :users
  # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
  root to: 'clients#index'
  resources :clients do
    resources :contacts
    collection do
      post :bulk_insert
    end
  end
end
```


# ビュー（該当部分のみ抜粋）
下から2行目のところにJSで登録するユーザーを追加していく形です。

```ruby:_main-contact-register-at-once.html.haml
.main-header
  .main-title
    コンタクト一括登録
.main-contents
  .form
    =form_with model:@contact, url:bulk_insert_clients_path,local: true do |f|
      .input-field
        = f.label 'カテゴリ', for: "act_cat"
        = f.collection_select :act_cat_id, ActCat.all, :id, :category, {include_blank: true},{id: "act_cat"}
      .input-field
        = f.label '詳細', for: "detail"
        = f.text_field :detail, id: "detail"
      .input-field
        = f.label '開始日', for: "start_date"
        = f.date_field :start_date, id: "start_date"
      .input-field
        = f.label '終了日', for: "end_date"
        = f.date_field :end_date, id: "end_date"
      .input-field
        = f.label '進行中'
        = f.select :in_progress,[["進行中",1], ["完了",0]],{},{id: "in_progress"}
      .register-wrapper
        .register-list
          .register-list__title
            クライアント一覧
          .register-list__box
            %table
              %tbody#client-list
                - @clients.each do |client|
                  %tr.register-list__element.client-list{data: {id: "#{client.id}",name: "#{client.client_name1+client.client_name2}"}}
                    %td
                      =client.client_name1 + client.client_name2
                    %td
                      →
        .register-list
          .register-list__title
            登録するクライアント
          .register-list__box
            %table
              %tbody#register-list
      = f.submit '登録',class: "form-btn" 
```
#JavaScript
hiddenでclient_idのテキストフィールドを追加しています。

```JavaScript:contact.js
$(function(){
  function addClient(clientId,clientName){
    var html = `<tr class="register-list__element candidate-list" data-id=${clientId} data-name=${clientName}>
                  <td>
                    ←
                  </td>
                  <td>
                    <input name='contact[client_ids][]' type='hidden' value='${clientId}'>
                  </td>
                  <td>
                    ${clientName}
                  </td>
                </tr>`
    return html;
  }
  function removeClient(clientId,clientName){
    var html = `<tr class="register-list__element client-list" data-id=${clientId} data-name=${clientName}>
                  <td>
                    ${clientName}
                  </td>
                  <td>
                    →
                  </>
                </tr>`
    return html;
  }
  $(document).on('click','tr.register-list__element.client-list',function(){
    $('#client-list').val();
    var clientId = (this).dataset.id;
    var clientName = (this).dataset.name;
    console.log(clientName);
    html = addClient(clientId,clientName);
    $('#register-list').append(html);
    $(this).remove();
  });
  $(document).on('click','tr.register-list__element.candidate-list',function(){
    $('#register-list').val();
    var clientId = (this).dataset.id;
    var clientName = (this).dataset.name;
    console.log(clientName);
    html = removeClient(clientId,clientName);
    $('#client-list').append(html);
    $(this).remove();
  });
  
});
```
#最後に（気になっているところ）
- 配列に入れるのはモデルにメソッド書いたほうが良かったかもしれないです。


#参考にした記事
https://qiita.com/makicamel/items/b6d4f3d2661fc66103ed