3
1

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 3 years have passed since last update.

Rails6でcocoonを使い、callbackが発火しなかったときの対処

Posted at

前提

 個人開発でcocoonというgemを使うことにした。入力フォームを作る際に、項目を簡単に増減できるお手軽gemだ。

 なんやかんやあって項目を増減することはできたが、callbackを実装するところで手間取った。自身のためにもすこし記録を残しておく。

やりたいこと

 gemはさくさく動くが、増減する項目数について制限を設けたかった。項目が0になってしまうのは捨てたいし、10個20個と追加できてしまうと見栄えが悪くなる。

 cocoonはcallbackを用意している。

Callbacks (upon insert and remove of items)

On insertion or removal the following events are triggered:

  • cocoon:before-insert: called before inserting a new nested child, can be canceled
  • cocoon:after-insert: called after inserting
  • cocoon:before-remove: called before removing the nested child, can be canceled
  • cocoon:after-remove: called after removal

Callbacks (upon insert and remove of items)--cocoon

項目の増減前にそれぞれイベントをつくることができ、いいかんじに制限してくれる。

いいな!やってみよ!

と思ったけどなぜかイベントが起こらなかった。

調査

 いろいろと調べることにした。cocoonは一応動作はしているので、gemがインストールされていないとか、環境設定が悪いとかそんなことではなさそうだった。まずは公式のissueから探っていった。

https://github.com/nathanvda/cocoon/issues/275
https://github.com/nathanvda/cocoon/issues/353

 これが一番参考になりそうだった。↓

開発者のnathanvdaさんがいろいろと回答していた。

from your code, I thought it could be a turbolinks problem? (using the ready event only, but in that case the click-event would also not be captured)
there is, by coincidence, not another event-handler that captures it first and stops propagation?

 railsのturbolinksにまつわる問題なのでは?callbackイベントの前に別のイベントが入って邪魔をしているのでは?

 質問者から回答があった。

dskvr commented on 21 Dec 2016

I feel like an idiot.
jQuery was being included twice, I didn't confirm this was the exact because I need to move like the wind at this point, but what I speculate is that the listeners were bound on a different instance of jQuery than Cocoon was firing the events from. How I didn't notice this before I have no idea. It took an accident and some snooping in adjacent partials to notice the discrepancy. (I hit my head against the table at the cafe for a good 10 minutes.)

 カフェで10分ほど頭をゴンゴンやっていたらしい。そこではない。「ちょっと勘違いしてたわ。jQueryを二重に読み込んでいたよ。なんできづかなかったかというと、ほにゃらら...」ちょっと英語は苦手だ。

stack over flowでもcocoonで検索してみた。「[cocoon-gem] callback」でいっぱいでてくる。

 驚きなのが大体の回答欄で開発者のひとが答えていることだった。このひとすごいな。

 だいたいポイントは一緒だった。

  • 単純なスペルミス
  • callbackを使うには要素をdivで囲んでおく必要がある
  • turbolinksの問題かもしれないので記載方法に注意する

修正

 回答を見ながら自分のコードを修正していった。viewファイルはそのままにした。

app/views/reports/new.html.erb
<!-- 略 -->
  <%= form_with model: @report, local: true do |f| %>
    <p>登録日:<%= f.date_field :reported_on , value:Date.today%></p>
    <div id="report_items">
      <%= f.fields_for :report_items do |item| %>
        <%= render "report_item_fields", f: item %>
      <% end %>
      <div class="links">
        <%= link_to_add_association "追加", f, :report_items %>
      </div>
    </div>
    <p>コメント:<%= f.text_field :content %></p>
    <%= f.submit "登録" %>
  <% end %>
<!-- 略 -->

JSファイルを修正した。

home.js
//$(document).ready(function() { 修正前 
$(document).on("page:load turbolinks:load", function() { //修正後
//...以下略

 turbolinksが読み込まれた後にイベントを出すようにした。これでもうまくいかなかった。

 スペルミスはとくになかった。その証拠に

$(document).on("page:load turbolinks:load", function() {
  $('#report_items').on('click', function() {
    console.log("click");
  });
//...略

 としたら動いた。クリックイベントは動いていた。

 ちょっとよくわからない。

真因

 さきのgithubのissueで誰かが言っていたことを思い出した。

jQuery was being included twice

 jQueryが二重に呼び出されているかもしれない。そもそもRails6はJSをどのように読み込んでいるのか。

 ここが参考になった。私はそれまでapplication.jsとは別のファイル(home.js)を作成し、そこにさきのcallbackを書いていた。

変更前

app/javascript/packs/
 - application.js
 - home.js   

そしてviewで以下のように設定していた。

app/views/layouts/application.html.erb
<!-- 略-->
   <head>
<!-- 略-->
    <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
    <%= javascript_pack_tag 'home' , 'defer':'true' %>
  </head>
<!-- 略-->

これがいけなかったのかもしれない。参考記事の方法1のように、application.jsにhome.jsの参照を追加させてみる。

変更後

app/javascript
  - packs
    - application.js
  - home.js (フォルダ移動)
app/views/layouts/application.html.erb
<!-- 略-->
   <head>
<!-- 略-->
    <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
  </head>
<!-- 略-->
app/javascript/packs/application.js
require("@rails/ujs").start()
require("turbolinks").start()
require("@rails/activestorage").start()
require("channels")

require("jquery")
require("@nathanvda/cocoon")

require ('home') //追加

結果

 callbackが発火するようになった。よかった。

 問題が起こったら公式を確認する、issueをみるというのは良いアプローチなんだなあと思った。

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?