Railsで使えるGem

Rails4でフォーム要素を動的に追加したり削除したり〜nested_form

投稿日:2014年1月20日 更新日:

参考

RailsCastsで紹介されてたフォームがGemになってたので試してみた

railscasts.com/episodes/196-nested-model-form-revised?view=asciicast

github.com/ryanb/nested_form

Rails4で 1対多、多対多関連しているときのフォームを作るなら、Nested Form Gemが便利

前提の環境

Modelにhas_manyとaccepts_nested_attributes_forが書いてある

関連するモデルの削除を許すなら allow_destroy: true オプションを付けておく

 

Gemfile

application.jsに追加

 

View

nested_form_forヘルパーが使える

link_to_addとlink_to_removeを配置する

READMEだとlink_to_addをpでくくってるけど、追加がうまくできなかった

Controller

Strong Paramatersで許可

このとき、:_destroyを許可しておく必要がある.

というのも、いったん追加したフォームはremoveしてもjqueryで隠しただけで、残っている.

そして、隠したフォームに、_destroyフラグをつけてsubmitしているため.

これがないと、いったん追加したあとに、removeしても、空欄のフォームのデータが追加されてしまうことになる.

できた

screenshot

パーシャル化

こんな感じでパーシャルに渡すこともできる このとき_task_fields.html.erbというファイル名のパーシャルを探しに行く

パーシャルにはfという変数に渡される

フォームを追加する場所を指定する

追加するフォームはaddリンクの直前に追加されるけど、これを任意の場所に追加するようにしてみる

追加するフォームにはdiv.fieldsというタグがつくので、これをつけないようにする

試しにtableでくくる このとき追加する場所を指定するためにidをつけておく

link_to_addでtarget指定する

パーシャルをtr要素にしておく このときにクラスにfieldsをつけておく これがないと削除できない

できた

screenshot

一対一の場合

一対一の場合、フォームを一個だけ追加して、あとは追加しないという処理を追加する必要がある.

その場合、jQueryのイベントを使えば簡単に対処できる.
例えば、追加するフィールドに名前をつけて(ここでは、#sakana)、、、

で、addで追加されるフォームはdiv.fieldsでくくられているので、#sakana以下の.fields数を数えて1を越える場合は削除してしまう.

試した環境は、Rails5.0.0.1+simple_formでした.

そのほか

addとremoveのときにjqueryイベントを呼べるとか、simple_formでも使えるとか

番外編: 1つのモデルで任意の数のデータを送信するフォームの作例

前提

views(form)

まず、new.html.erbを作成する.
form_tagでサブミットボタンとQ&Aが貼られる場所、Q&Aの追加リンクを準備する.

routes

add_pathを作成.

controller

qandasコントローラにaddアクションを作成する.

views(js.coffeeテンプレート)

add.js.coffeeテンプレートを作成する.

views(パーシャル)

_qanda.html.erbを作成する.
ついでに、削除リンクを作っておく.

controller(create)

createアクションを作る.
できたフォームで送信されるデータは、こんな感じ.

これにあわせてStrongParameterとcreateを作成.

できた.

screenshot_from_2016-10-30-174251

-Railsで使えるGem
-,

執筆者:

  • 西田 龍

    質問させていただきます。

    このgemでは、一対多、多対多でないと、フォームを動的に追加、削除出来ないのでしょうか?

    回答よろしくお願いします。

    • 質問ありがとうございます.
      試してないですが、おそらく一対一でも、できると思います.
      もしかして質問の趣旨はそういう意味じゃなかったでしょうか?

      記事に一対一のケースを追記しました.
      フォームを追加してから削除するという無駄をしているので、本当はソースをいじった方がいいかもしれません.

      • 西田 龍

        回答ありがとうございます。
        僕の言ってるのは関係データベースのようなものでなく、
        普通のモデルでの話です。
        そのような環境では、このgemを、活用することは出来ないのでしょうか?
        具体的には以下のようにしたいのです。

        teratail.com/questions/53198

        回答よろしくお願いします。

        • リンク先みました.

          質問の趣旨は、1つのモデル(word)で、任意の数のデータ(words)を送信するのにこのgemを使いたいということでしょうか?

          そのまま、このgemを使うのは難しいと思います.

          1つのアイデアとして、関連先を無理やり使うということはできないでしょうか?

          例えば、wordがuserなどに従属している場合(has_many :words)

          にして、そのユーザーが投稿する質問と回答を投稿、編集するフォームとして使うという方法です.

          また、元のRailscastの動画をみればわかるのですが、このgemはrailsのaccepts_nested_attributes_forの投稿規約にあわせて、jQueryでフォームを操作しているだけですので、同じ要領でgemを使わずにスクラッチで実現することもできると思います.

          その場合は、Railscastの次の動画が参考になると思います.
          チェックボックスで選んだ複数のデータを一度に更新するというテーマの回です.

          railscasts.com/episodes/198-edit-multiple-individually?view=asciicast

          • 西田 龍

            回答ありがとうございます。
            ふと思ったんですが、JavaScript を利用して、該当部分のerbを、吐かせるのが一番簡単ではないかと。
            しかし、erbを、JavaScript を利用して、吐かせることはできるんですか?

            できる場合、参考になるページなどご存知ありませんか?

          • そこはたぶん簡単です.
            remoteなリンク(画面遷移させない)を作って、対象のコントローラから、*.js.coffeeという名前のviewを呼び出して、そこで、パーシャルをrenderすればいいだけです.

            blog.scimpr.com/2013/01/11/rails3-2%e3%81%a7coffeescript%e3%82%92erb%e3%83%86%e3%83%b3%e3%83%97%e3%83%ac%e3%83%bc%e3%83%88%e3%81%a8%e3%81%97%e3%81%a6%e4%bd%bf%e3%81%86%e4%bb%b6/

            blog.scimpr.com/2012/09/06/rails3%e9%83%a8%e5%88%86%e3%83%86%e3%83%b3%e3%83%97%e3%83%ac%e3%83%bc%e3%83%88%e3%81%a8ajax%e5%8c%96%e3%81%ae%e3%81%be%e3%81%a8%e3%82%81/

            大変なのが複数データを作成するフォームとコントローラだと思います.
            下記のページを参考にform_tagを使うときは、fields_forタグにindex:nilオプションを渡すとうまく複数データを送信できるみたいでした.

            319ring.net/blog/archives/2591/

            適当ですが、作例を記事に追加しました.
            参考になれば.

          • 西田 龍

            更新してくださったんですね!
            ありがとうございます!
            参考にさせていただきます👏🏻

          • 西田 龍

            何度もすみません。参考に実装してみたのですがうまくいきません。

            gyazo.com/d12556e1557331ee2b078b2500867716

            状態としては上記のようになっています。

            ソース:
            github.com/NishidaRyu416/share-tan/tree/words_view_system/app

            回答お願いします

          • パソコンが触れない環境なのでこれで動くかわからないですが、

            とりあえず、add.js.coffeeはapp/views/words/以下に置いてみてください

            erbを展開したいときは、assets以下ではなく、views以下に配置します

            たぶん、そこを修正しても、エラーは1つもフォームを追加しないときには相変わらず出ると思います。コントローラーで判定するか、Javascriptで少なくとも1つフォームがないとボタンを押せないようにするか、するといいと思います

          • 西田 龍

            無事できました!
            本当にありがとうございました!

          • 西田 龍

            わかりました。
            追加関連はやってみます。
            削除ボタンでformが全て削除されてしまいます。
            これはどうすればいいですかね?
            一つずつ消したいのですが・・

  • 西田 龍

    更新してくださったんですね!
    ありがとうございます!
    参考にさせていただきます👏🏻

  • 西田 龍

    何度もすみません。
    nested_form 内で が うまくいかないのですが、解決策ご存じですか?

  • 西田 龍

    できてみて確認したんですけど、追加をしてから削除して、formが再び0個の時、formを追加することができません。また、削除ボタンでformが全て削除されてしまいます。jsが僕はよくわからないので、どうすれば直りますか?

    • いい感じにできてきましたね!

      _qanda.htm.erbのフォームを私の例のように、divで囲んでみてください.
      JavaScriptでやっているのはRemoveリンクの親要素を削除しているのです.
      今は、div#qandasがRemoveリンクの直接の親要素になってしまっています.

      • 西田 龍

        わかりました。
        フォームが、0の状態の時を判定したいんですが、jsが、わからないんで書けないので、jsを、書いていただけませんか?

        仕様としてはform追加ボタンを押すと変数が++し、フォーム削除ボタンを押すと変数が–する。
        変数をgetterメソッドで取得、そして、変数が0の時はブラウザをreloadし、それ以外の時は変数を減らす
        このように考えています。

  • 西田 龍

関連記事

no image

Rails3.2でユーザー権限を細かく設定~Devise + cancan

      参考 cancan でモテカワ♥愛され権限管理 How To: Integrate with CanCan for roles management &nbs …

テキストマイニングの初歩 Rubyで形態素解析を行う〜ruby-mecab

By: Cracker Jack – CC BY 2.0 環境 ubuntu server 12.04 英語は単語を空白で区切るのでコンピュータでの解析に向いているが、日本語は助詞などを続 …

今度こそRails3.2からdocxを生成する

  前提 Rubyからdocxを生成する 前回、イキオイアマって自分でdocxを生成する簡単なライブラリを作ってしまった.(なんて車輪の再発明 今回はこれをRailsから利用してみる. 目次 …

no image

Rails4でOpenDocumentText(.odt)を作成~serenity(未完)

StackOverFlowでの質問に返事が来てたよ!ヽ(=´▽`=)ノ stackoverflow.com/questions/13080178/encodingundefinedconversion

no image

Mongoidで地理情報インデックスを使おうとしたけどうまくいかない

試したgem mongoid_geo mongoid_geospatial 試してないgem mongoid_spacial