営業職の俺がエンジニアになる〜群馬Web化計画編〜

2017年に未経験からエンジニアに転職をした私が群馬でイノベーションを起こすまでの備忘録です。

cocoonをRails5.1で使用しようと思った時にハマる罠

最近新しいアプリケーションの開発を進めています。このアプリケーションを作成するにあたり「Gemがあればとにかく使って実装」という方針で進めています。Knowledge Stockerを実装する際はどちらかと言うと「自分で書いて実装してみる」という流れで作っていたので、Gemに慣れるという密かな目的を推進しています。

そんな中、accepts_nested_attributes_forを使いネストしたフォームを作る際に、フォームを非同期的に追加、削除するという動作が必要となったためcocoonというGemを使ってみました。そこでハマった内容を備忘録的な感じにまとめてみました。

cocoonとは

先程触れたように、ネストしたフォームを非同期的に追加、削除を行うためのGemです。色々と調べてみると、これまではnested_formを使って実装をすることが流行っていたようなのですが、Gemのアップデートが4、5年前から止まっており、cocoonに乗り換える方々も多い模様。直近サポートされていないGemよりもサポートされているGemの方が安心だろうということでcocoonを使ってみることにしました。

使ってみた

英語が読めないながらも必死にREADMEを見ながら設定をしていきました。設定方法は意外とシンプルで

  1. Gemをインストール
  2. application.jsを設定
  3. ModelやControllerを設定
  4. cocoonの書き方に従ったフォームの作成

をするだけとのこと。(念のため手順は下記に記載します)

環境

Gemのインストール

Gemfilecocoonを追加しbundle install

gem "cocoon"
$ bundle install

application.jsの設定

application.jsに下記の一文を追加。

//= require cocoon

Modelの設定

Modelを下記のとおりに設定する。

class Plan < ActiveRecord::Base
  has_many :locations, inverse_of: :plan
  accepts_nested_attributes_for :locations, reject_if: :all_blank, allow_destroy: true
end

class Location < ActiveRecord::Base
  belongs_to :plan
end

Controllerの設定

ControllerのStrong Parametersを下記の通り設定する。

def plan_params
  params.require(:plan).permit(:name, :description, locations_attributes: [:id, :name, :description, :_destroy])
end

フォームを作成

cocoonの仕様に従い下記の通りフォームを作成します。

app/views/plans/_form.html.slim

= form_with model: @plan, local: true do |f|
  - if @plan.errors.any?
    ul.error-explanation
      - @plan.errors.full_messages.each do |message|
        li= message
  .form-group
    = f.label :name
    = f.text_field :name, class: "form-control"
  .form-group
    = f.label :description
    = f.text_area :description, class: "form-control"
  h2 = t("view.spot_registration")
  = f.fields_for :locations do |location|
    = render "location_fields", f: location
  .links
    = link_to_add_association f, :locations, class: "btn btn-primary btn-add"
  = f.submit class: "btn btn-primary"

app/views/plans/_location_fields.html.slim

.nested-fields
  .form-group
    = f.label :name
    = f.text_field :name, class: "form-control"
  .form-group
    = f.label :description
    = f.text_area :description, class: "form-control"
  = link_to_remove_association f, class: "btn btn-danger btn-remove"

この時に必ず用意しなければならないのは下記の3つのようです。

  • _{model}_fields.html.slimというパーシャル
  • 上記パーシャルへnested-fieldsというclassを設定する
  • =link_to_add_attributesの前にlinksというclassを設定する

cocoon × Rails 5.1の罠

さて上記の設定が完了したので、実際に動くかどうか試してみよう!と思いフォームの追加ボタン、削除ボタンをポチッとな!

ポチッ!ポチ!ポチ!ポチ!

無反応・・・

そうなんです。このままでは動かないのです。この罠にハマりました。Javascriptが動いていないはなんとなくわかったのですが、何故動かないのかが、分からず色々と調べてみました。するとRails 5.1からjQeryをサポートしていないという情報に行き着くことに。そしてcocoonjQueryを前提に作られているというのをREADMEで見たような・・・!!

そうなんです。cocoonjQueryを使っているのでRails 5.1の標準の状態では動かないのです。という訳でRails 5.1でjQueryが動くように設定をしてあげました。

jQueryの設定

Rails 5.1でjQueryを動かすにはjquery-railsというGemをインストールしてあげます。

gem "jquery-rails"

そしてapplication.jsに下記を追加します。

//= require jquery

これで準備完了!そしてフォームの追加ボタン、削除ボタンを押してみると、、、見事動きました!ということで、無事、cocoonを導入することが出来ました。

しかしながら、今後RailsjQueryをサポートしないことを考えるとcocoonを導入する事自体も考えなければならなそうですね。以上、色々と勉強になった1日でした。