見出し画像

【44】【Rails】cocoon公式ドキュメントの翻訳記事

この記事はgem cocoon公式ドキュメントの翻訳記事です。
(注意:noteは埋め込みコード内のコメントが非常に見ずらいです。
よってコード内のコメントを一部直書きしています。ご了承下さい。)

ドキュメント読んでも分かりづらかったので、どんな機能のgemなのか下記サイトを見てイメージを掴むと良いかと思います。

https://www.y-hakopro.com/entry/2019/08/03/234126
https://qiita.com/tanutanu/items/a9f435e33b2d4533b3a2

Cocoon makes it easier to handle nested forms.
Nested forms are forms that handle nested models and attributes in one form; e.g. a project with its tasks or an invoice with its line items.
Cocoon is form builder-agnostic, so it works with standard Rails, Formtastic, or SimpleForm. It is compatible with rails 3, 4 and 5.
This project is not related to Apache Cocoon.

Cocoonでは、入れ子になったフォームを簡単に扱うことができる。
入れ子になったフォームとは、入れ子になったモデルや属性を一つのフォームで扱うフォームのことで、例えば、プロジェクトとタスク、請求書と請求項目などがある。
Cocoonはフォームビルダーに依存しないので、標準的なRails、Formtastic、SimpleFormで動作する。rails 3, 4, 5に対応しています。
このプロジェクトは、Apache Cocoonとは関係ありません。

Prerequisites

This gem depends on jQuery, so it's most useful in a Rails project where you are already using jQuery. Furthermore, I would advise you to use either Formtastic or SimpleForm.

前提条件
このgemはjQueryに依存しているので、すでにjQueryを使用しているRailsプロジェクトで最も有効です。さらに、FormtasticかSimpleFormを使うことをお勧めします。

Installation

Inside your Gemfile add the following:

gem "cocoon"

Rails 6/Webpacker
Add the companion package

yarn add @nathanvda/cocoon

and then in your app/javascripts/packs/application.js you should add

require("jquery")
require("@nathanvda/cocoon")
Note: there are alternative npm packages, which might better suit your needs. E.g. some offer the cocoon functionality without using jquery (search for cocoon + vanilla --I found three packages on npm already). Obviously you are free to use those, however the code samples in this README will (still) rely on jquery.

注:他のnpmパッケージもあるので、そちらの方がニーズに合うかもしれません。例えば、jqueryを使わずにcocoonの機能を提供しているものがあります(cocoon + vanillaで検索すると、すでにnpmで3つのパッケージが見つかりました)。もちろん、これらのパッケージを使用することは自由ですが、このREADMEに記載されているコードサンプルは(まだ)jqueryに依存しています。

Basic Usage

Suppose you have a Project model:
基本的な使い方
Projectモデルがあるとします。

rails g scaffold Project name:string description:string

And a project has many tasks:
rails g model Task description:string done:boolean project:belongs_to

Your models are associated like this:

class Project < ActiveRecord::Base
 has_many :tasks, inverse_of: :project
 accepts_nested_attributes_for :tasks, reject_if: :all_blank, allow_destroy: true
end

class Task < ActiveRecord::Base
 belongs_to :project
end
Rails 5 Note: since rails 5 a belongs_to relation is by default required. While this absolutely makes sense, this also means associations have to be declared more explicitly. When saving nested items, theoretically the parent is not yet saved on validation, so rails needs help to know the link between relations. There are two ways: either declare the belongs_to as optional: false, but the cleanest way is to specify the inverse_of: on the has_many. That is why we write : has_many :tasks, inverse_of: :project

Rails 5 Note: rails 5からは、デフォルトで belongs_toリレーションが必要になりました。
これは非常に理にかなっていますが、これは関連性をより明示的に宣言しなければならないことを意味します。
ネストしたアイテムを保存するとき、理論的には親は検証時にはまだ保存されていないので、関係間のリンクを知るためにrailsは助けを必要とします。2つの方法があります: belongs_toをoptional: falseと宣言するか、最もクリーンな方法はhas_manyにinverse_of: を指定することです。
そのため、次のように記述します: has_many :tasks, inverse_of: :project

Now we want a project form where we can add and remove tasks dynamically. To do this, we need the fields for a new or existing task to be defined in a partial named _task_fields.html.

今度は、タスクを動的に追加したり削除したりできるプロジェクトフォームを作りたいと思います。そのためには、新規または既存のタスクのフィールドを _task_fields.html という名前のパーシャルで定義する必要があります。

Strong Parameters Gotcha

To destroy nested models, rails uses a virtual attribute called _destroy. When _destroy is set, the nested model will be deleted. If the record is persisted, rails performs id field lookup to destroy the real record, so if id wasn't specified, it will treat current set of parameters like a parameters for a new record.
When using strong parameters (default in rails 4), you need to explicitly add both :id and :_destroy to the list of permitted parameters.

ストロングパラメータの問題
railsでは、入れ子になったモデルを破壊するために、_destroyという仮想属性を使います。
destroyが設定されると、入れ子のモデルが削除されます。レコードが永続化されている場合、railsはidフィールドのルックアップを行って実際のレコードを破棄しますので、
idが指定されていない場合は、現在のパラメータセットを新しいレコードのパラメータのように扱います。
strong parametersを使用する場合(rails 4のデフォルト)、許可されるパラメータのリストに:idと:_destroyの両方を明示的に追加する必要があります。

 def project_params
   params.require(:project).permit(:name, :description, tasks_attributes: [:id, :description, :done, :_destroy])
 end

Has One Gotcha

If you have a has_one association, then you (probably) need to set force_non_association_create: true on link_to_add_association
If you don't do this, then rails will automatically delete your existing association when you view the edit form!
More details in the wiki

Has Oneの問題点
has_oneアソシエーションがある場合、(おそらく)link_to_add_associationにforce_non_association_create: trueを設定する必要があります。
これを設定しないと、編集フォームを表示したときに、既存のアソシエーションが自動的に削除されてしまいます。
詳細はwikiを参照してください。

Examples

Cocoon's default configuration requires link_to_add_association and associated partials to be properly wrapped with elements. The examples below illustrate simple layouts.
Please note these examples rely on the haml gem (click here for the default erb views).


Cocoonのデフォルトの設定では、link_to_add_associationとそれに関連するパーシャルが適切に要素でラップされている必要がある。以下の例は簡単なレイアウトの例である。

これらの例はhaml gemに依存していることに注意してほしい(デフォルトのerbビューはここをクリック)。
(訳注:hamlの書式は割愛し、erbビューのみ書いてます。)

erb_Usage

This is the same section from the README but translated to ERB, just in case HAML is unknown or unfamiliar. Please compare the following code-morcels with HAML, and I hope it will urge you to go learn HAML :)
Using formtastic
Inside our projects/_form partial we then write:

使い方
ここでは、HAMLを知らない人のために、READMEの同じセクションをERBに翻訳しています。以下のコードモックルをHAMLと比較して、HAMLを学ぶきっかけにしてください。)

Using formtastic

projects/_form partialの中に、次のように書きます。

<%= semantic_form_for @project do |f| %>
  <% f.inputs do %>
    <%= f.input :name %>
    <%= f.input :description %>
    <h3>Tasks</h3>
    <div id='tasks'>
      <%= f.semantic_fields_for :tasks do |task| %>
        <%= render 'task_fields', :f => task %>
      <% end %>
      <div class='links'>
        <%= link_to_add_association 'add task', f, :tasks %>
      </div>
    </div>
    <% f.buttons do %>
      <%= f.submit 'Save' %>
    <% end %>
  <% end %>
<% end %>
and inside the _task_fields partial we write:
<div class='nested-fields'>
 <%= f.inputs do %>
   <%= f.input :description %>
   <%= f.input :done, :as => :boolean %>
   <%= link_to_remove_association "remove task", f %>
 <% end %>
</div>

Using SimpleForm
Inside our projects/_form partial we then write:

<%= simple_form_for @project do |f| %>
 <%= f.input :name %>
 <%= f.input :description %>
 <h3>Tasks</h3>
 <div id='tasks'>
   <%= f.simple_fields_for :tasks do |task| %>
     <%= render 'task_fields', :f => task %>
   <% end %>
   <div class='links'>
     <%= link_to_add_association 'add task', f, :tasks %>
   </div>
 </div>
 <%= f.submit 'Save' %>
<% end %>
and inside the _task_fields partial we write:
<div class='nested-fields'>
   <%= f.input :description %>
   <%= f.input :done, :as => :boolean %>
   <%= link_to_remove_association "remove task", f %>
</div>

Using standard rails forms
Inside our projects/_form partial we then write:

<%= form_for @project do |f| %>
 <div class="field">
   <%= f.label :name %>
   <br/>
   <%= f.text_field :name %>
 </div>
 <div class="field">
   <%= f.label :description %>
   <br/>
   <%= f.text_field :description %>
 </div>
 <h3>Tasks</h3>
 <div id='tasks'>
   <%= f.fields_for :tasks do |task| %>
     <%= render 'task_fields', :f => task %>
   <% end %>
   <div class='links'>
     <%= link_to_add_association 'add task', f, :tasks %>
   </div>
 </div>
 <%= f.submit 'Save' %>
<% end %>

and inside the _task_fields partial we write:

 <div class='nested-fields'>
   <div class="field">
     <%= f.label :description %>
     <%= f.text_field :description %>
   </div>
   <div class="field">
     <%= f.check_box :done %>
     <%= f.label :done %>
   </div>
   <%= link_to_remove_association "remove task", f %>
 </div>

How it works

Cocoon defines two helper functions:
(仕組み Cocoonでは2つのヘルパー関数が定義されている。)

link_to_add_association
This function adds a link to your markup that, when clicked, dynamically adds a new partial form for the given association. This should be called within the form builder.

この関数は、あなたのマークアップにリンクを追加します。このリンクがクリックされると、指定されたアソシエーションのための新しいパーシャルフォームが動的に追加されます。この関数は、フォームビルダーの中で呼び出されます。
link_to_add_association takes four parameters:
(link_to_add_associationは4つのパラメータを受け取ります。)

name
: the text to show in the linkname:
リンクに表示するテキスト
f
: the form builder
フォームビルダー
association
: the name of the association (plural) of which a new instance needs to be added (symbol or string).
新しいインスタンスを追加する必要のあるアソシエーション(複数可)の名前(シンボルまたは文字列)。
html_options
: extra html-options (see link_to There are some special options, the first three allow to control the placement of the new link-data:
追加のhtmlオプション(link_to参照) いくつかの特別なオプションがあり、最初の3つは新しいリンクデータの配置を制御することができます。
data-association-insertion-traversal 
 : the jquery traversal method to allow node selection relative to the link. closest, next, children, etc. Default: absolute selection
リンクに対する相対的なノードの選択を可能にするjqueryのトラバーサルメソッドです。デフォルト:absolute selection
data-association-insertion-node 
 : the jquery selector of the node as string, or a function that takes the link_to_add_association node as the parameter and returns a node. Default: parent node
ノードのjqueryセレクタを文字列で指定するか、link_to_add_associationノードをパラメータとし、ノードを返す関数を指定する。
デフォルト:parent node
data-association-insertion-method
: jquery method that inserts the new data. before, after, append, prepend, etc. Default: before
新しいデータを挿入するjqueryのメソッドです。
デフォルト:before
data-association-insertion-position
: old method specifying where to insert new data.
this setting still works but data-association-insertion-method takes precedence. may be removed in a future version.
新しいデータを挿入する場所を指定する古い方法です。
将来のバージョンでは削除される可能性もありますが、この設定はまだ機能しますが、data-association-insertion-methodが優先されます。
partial
: explicitly declare the name of the partial that will be used
使用されるパーシャルの名前を明示的に宣言します。
render_options
 : options passed through to the form-builder function (e.g. simple_fields_for, semantic_fields_for or fields_for). If it contains a :locals option containing a hash, that is handed to the partial.
フォームビルダー関数に渡されるオプション(例:simple_fields_for、semantic_fields_for、fields_for)。もし、ハッシュを含む :locals オプションが含まれていれば、それはパーシャルに渡されます。
wrap_object
 : a proc that will allow to wrap your object, especially useful if you are using decorators (e.g. draper). See example lower.
デコレーター(draperなど)を使っている場合に便利な、オブジェクトをラップするためのプロックです。下の例を参照してください。
force_non_association_create
: if true, it will not create the new object using the association (see lower)
form_name
trueの場合、アソシエーションを使用した新しいオブジェクトを作成しません(下部参照)。
 : the name of the form parameter in your nested partial. By default this is f.
入れ子になったパーシャルのフォームパラメータの名前です。デフォルトでは、これはfです。
count
: the number of nested items to insert at once. Default 1.
一度に挿入する入れ子の数を指定します。デフォルトは1です。

Optionally, you can omit the name and supply a block that is captured to render the link body (if you want to do something more complicated).

(オプションとして、名前を省略して、リンクボディをレンダリングするためにキャプチャされたブロックを指定することもできます(より複雑なことをしたい場合)。)

:render_options
Inside the html_options you can add an option :render_options, and the containing hash will be handed down to the form builder for the inserted form.
When using Twitter Bootstrap and SimpleForm together, simple_fields_for needs the option wrapper: 'inline' which can be handed down as follows:
(Note: In certain newer versions of simple_form, the option to use is wrapper: 'bootstrap'.)

:render_options
html_optionsの中にオプション:render_optionsを追加すると、含まれるハッシュが挿入されたフォームのフォームビルダーに引き渡されます。
Twitter BootstrapとSimpleFormを併用する場合、simple_fields_forにはオプションのラッパー:'inline'が必要で、これは以下のようにして引き渡すことができます。
(注意: simple_formのある新しいバージョンでは、使用するオプションはwrapper: 'bootstrap'です。)

= link_to_add_association 'add something', f, :something,
   render_options: { wrapper: 'inline' }

To specify locals that needed to handed down to the partial:
(パーシャルに受け継がれるべきローカルを特定する)

= link_to_add_association 'add something', f, :something,
   render_options: {locals: { sherlock: 'Holmes' }}

:partial
To override the default partial name, e.g. because it shared between multiple views:
(複数のビューで共有されているなどの理由で、デフォルトのパーシャル名を上書きするには、次のようにします。)

= link_to_add_association 'add something', f, :something,
    partial: 'shared/something_fields'
:wrap_object
If you are using decorators, the normal instantiation of the associated object will not be enough. You actually want to generate the decorated object.
A simple decorator would look like:

デコレータを使用している場合、通常の関連オブジェクトのインスタンス化だけでは不十分です。デコレーションされたオブジェクトを実際に生成したいのです。
シンプルなデコレータは次のようになります。

class CommentDecorator
 def initialize(comment)
   @comment = comment
 end

 def formatted_created_at
   @comment.created_at.to_formatted_s(:short)
 end

 def method_missing(method_sym, *args)
   if @comment.respond_to?(method_sym)
     @comment.send(method_sym, *args)
   else
     super
   end
 end
end

To use this:
= link_to_add_association('add something', @form_obj, :comments,
   wrap_object: Proc.new {|comment| CommentDecorator.new(comment) })
Note that the :wrap_object expects an object that is callable, so any Proc will do. So you could as well use it to do some fancy extra initialisation (if needed). But note you will have to return the (nested) object you want used. E.g

なお、:wrap_objectは呼び出し可能なオブジェクトを想定していますので、どんなProcでも構いません。そのため、(必要に応じて)特別な初期化を行うために使用することもできます。ただし、使用したい(ネストされた)オブジェクトを返さなければならないことに注意してください。例えば、以下のようになります。

= link_to_add_association('add something', @form_obj, :comments,
   wrap_object: Proc.new { |comment| comment.name = current_user.name; comment })
:force_non_association_create
In normal cases we create a new nested object using the association relation itself. This is the cleanest way to create a new nested object.
This used to have a side-effect: for each call of link_to_add_association a new element was added to the association. This is no longer the case.
For backward compatibility we keep this option for now. Or if for some specific reason you would really need an object to be not created on the association, for example if you did not want after_add callback to be triggered on the association.

通常のケースでは、アソシエーション・リレーション自体を使って新しい入れ子のオブジェクトを作成します。これは、新しい入れ子のオブジェクトを作成する最もきれいな方法です。
以前は、link_to_add_associationを呼び出すたびに、新しい要素が関連に追加されるという副作用がありました。これはもうありません。
後方互換性のために、今のところこのオプションを維持しています。また、何らかの特別な理由で、アソシエーション上にオブジェクトを作成しないようにする必要がある場合、例えば、アソシエーション上でafter_addコールバックをトリガーしたくない場合などがあります。

Example use:

= link_to_add_association('add something', @form_obj, :comments,
   force_non_association_create: true)

By default :force_non_association_create is false.
(デフォルトでは :force_non_association_create は false です。)

link_to_remove_association

This function will add a link to your markup that, when clicked, dynamically removes the surrounding partial form. This should be placed inside the partial _<association-object-singular>_fields.
It takes three parameters:
name: the text to show in the link
f: referring to the containing form-object
html_options: extra html-options (see link_to)
Optionally you could also leave out the name and supply a block that is captured to give the name (if you want to do something more complicated).
Optionally, you can add an html option called wrapper_class to use a different wrapper div instead of .nested-fields. The class should be added without a preceding dot (.).

関連付けを解除するためのリンク
この関数は、あなたのマークアップにリンクを追加し、それがクリックされると、周囲のパーシャルフォームを動的に削除します。これは、パーシャルの_<association-object-singular>_fieldsの中に置かれなければなりません。これは3つのパラメータを取ります。
name:
 リンクで表示するテキスト
f:
 含まれるフォームオブジェクトを参照する
html_options:
 追加のhtml-options (link_to参照)
オプションとして、名前を省略して、名前を与えるためにキャプチャされたブロックを供給することもできます(もっと複雑なことをしたい場合)。
オプションとして、wrapper_classというhtmlオプションを追加して、.nested-fieldsの代わりに別のラッパーdivを使用することもできます。このクラスは、前にドット(.)を付けずに追加してください。

Note: the javascript behind the generated link relies on the presence of a wrapper class (default .nested-fields) to function correctly.

注意:生成されたリンクの背後にあるjavascriptは、正しく機能するために、ラッパークラス(デフォルトの.nested-fields)の存在に依存しています。
Example:

= link_to_remove_association('remove this', @form_obj,
 { wrapper_class: 'my-wrapper-class' })

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
: 削除後に呼び出されます。

To listen to the events in your JavaScript:
(JavaScriptでイベントをリッスンするために。)

 $('#container').on('cocoon:before-insert', function(e, insertedItem, originalEvent) {
   // ... do something
 });
...where e is the event and the second parameter is the inserted or removed item. This allows you to change markup, or add effects/animations (see example below). originalEvent is also passed and references the event that triggered an insertion or removal (e.g. the click event on the link to add an association)

...e はイベント、2 番目のパラメータは挿入または削除されたアイテムです。originalEventも渡され、挿入や削除のきっかけとなったイベントを参照します(例:関連を追加するリンクのクリックイベント)。

If in your view you have the following snippet to select an owner:
ビューにオーナーを選択するための次のようなスニペットがあるとします。

#owner
 #owner_from_list
   = f.association :owner, collection: Person.all(order: 'name'), prompt: 'Choose an existing owner'
 = link_to_add_association 'add a new person as owner', f, :owner


This will either let you select an owner from the list of persons, or show the fields to add a new person as owner.
The callbacks can be added as follows:
これにより、人物リストからオーナーを選択するか、新しい人物をオーナーとして追加するためのフィールドが表示されます。
コールバックは以下のように追加できます。

$(document).ready(function() {
   $('#owner')
     .on('cocoon:before-insert', function() {
       $("#owner_from_list").hide();
       $("#owner a.add_fields").hide();
     })
     .on('cocoon:after-insert', function() {
        ... do something ... 
     })
     .on("cocoon:before-remove", function() {
       $("#owner_from_list").show();
       $("#owner a.add_fields").show();
     })
     .on("cocoon:after-remove", function() {
        e.g. recalculate order of child items */
         例えば、子アイテムの順番を再計算する */
     });

    example showing manipulating the inserted/removed item
     挿入/削除されたアイテムを操作する例
   $('#tasks')
     .on('cocoon:before-insert', function(e,task_to_be_added) {
       task_to_be_added.fadeIn('slow');
     })
     .on('cocoon:after-insert', function(e, added_task) {
        e.g. set the background of inserted task
        例:挿入されたタスクの背景を設定する
       added_task.css("background","red");
     })
     .on('cocoon:before-remove', function(e, task) {
        allow some time for the animation to complete
         アニメーションが完了するまで時間を置く
       $(this).data('remove-timeout', 1000);
       task.fadeOut('slow');
     });
});

Note that for the callbacks to work there has to be a surrounding container to which you can bind the callbacks.
When adding animations and effects to make the removal of items more interesting, you will also have to provide a timeout. This is accomplished by the following line:

なお、コールバックを動作させるためには、コールバックをバインドできる周囲のコンテナが必要です。
アイテムの削除をより面白くするためにアニメーションやエフェクトを追加する場合は、タイムアウトを設定する必要があります。これは次の行で実現します。

$(this).data('remove-timeout', 1000);

You could also immediately add this to your view, on the .nested-fields container (or the wrapper_class element you are using).
(また、ビューの.nested-fieldsコンテナ(または、使用しているwrapper_class要素)に、すぐにこれを追加することもできます。)

For example:

 $('#container').on('cocoon:before-insert', function(event, insertedItem) {
   var confirmation = confirm("Are you sure?");
   if( confirmation === false ){
     event.preventDefault();
   }
 });

Control the Insertion Behaviour

The default insertion location is at the back of the current container. But we have added two data- attributes that are read to determine the insertion-node and -method.

挿入時の動作を制御する
デフォルトの挿入位置は、現在のコンテナの後ろ側です。しかし、挿入ノードと挿入方法を決定するために読み取られる2つのデータ属性を追加しています。
For example:

$(document).ready(function() {
   $("#owner a.add_fields").
     data("association-insertion-method", 'before').
     data("association-insertion-node", 'this');
});
The association-insertion-node will determine where to add it. You can choose any selector here, or specify this. Also, you can pass a function that returns an arbitrary node. The default is the parent-container, if you don't specify anything.
The association-insertion-method will determine where to add it in relation with the node. Any jQuery DOM Manipulation method can be set but we recommend sticking to any of the following: before, after, append, prepend. It is unknown at this time what others would do.
The association-insertion-traversal will allow node selection to be relative to the link.

association-insertion-nodeでは、どこに追加するかを決定します。ここでは、任意のセレクタを選ぶことも、これを指定することもできます。また、任意のノードを返す関数を渡すこともできます。何も指定しない場合のデフォルトは親コンテナです。

association-insertion-methodは、ノードとの関連でどこに追加するかを決定します。jQueryのDOM Manipulationメソッドであれば何でも設定できますが、before、after、append、prependのいずれかを指定することをお勧めします。他の人がどうするかは今のところ不明です。

association-insertion-traversalでは、ノードの選択をリンクに対して相対的に行うことができます。
For example:

$(document).ready(function() {
   $("#owner a.add_fields").
     data("association-insertion-method", 'append').
     data("association-insertion-traversal", 'closest').
     data("association-insertion-node", '#parent_table');
});
(if you pass association-insertion-node as a function, this value will be ignored)
Note, if you want to add templates to the specific location which is:
not a direct parent or sibling of the link
the link appears multiple times - for instance, inside a deeply nested form
you need to specify association-insertion-node as a function.
For example, suppose Task has many SubTasks in the Example, and have subtask forms like the following.
(Association-insertion-nodeを関数として渡した場合、この値は無視されます)

注意:テンプレートを特定の場所に追加したい場合は、以下の点に注意してください。
リンクの直接の親でも兄弟でもない。
リンクが複数回表示されている (例えば、深く入れ子になったフォームの中など)の場合は、関数としてAssociation-insertion-nodeを指定する必要があります。
例えば、例題でタスクが多くのサブタスクを持ち、以下のようなサブタスクのフォームを持っているとします。

.row
 .col-lg-12
   .add_sub_task= link_to_add_association 'add a new sub task', f, :sub_tasks
.row
 .col-lg-12
   .sub_tasks_form
     fields_for :sub_tasks do |sub_task_form|
       = render 'sub_task_fields', f: sub_task_form

Then this will do the thing.

$(document).ready(function() {
   $(".add_sub_task a").
     data("association-insertion-method", 'append').
     data("association-insertion-node", function(link){
       return link.closest('.row').next('.row').find('.sub_tasks_form')
     });
});

Partial

If no explicit partial name is given, cocoon looks for a file named _<association-object_singular>_fields. To override the default partial use the :partial option.
For the JavaScript to behave correctly, the partial should start with a container (e.g. div) of class .nested-fields, or a class of your choice which you can define in the link_to_remove_association method.
There is no limit to the amount of nesting, though.

パーシャル
明示的なパーシャル名が与えられていない場合、cocoonは_<association-object_singular>_fieldsという名前のファイルを探します。デフォルトのパーシャルを上書きするには、:partialオプションを使います。
JavaScriptが正しく動作するためには、パーシャルの先頭に、クラス.nested-fieldsのコンテナ(divなど)、またはlink_to_remove_associationメソッドで定義した任意のクラスが必要です。
ただし、入れ子の数に制限はありません。

I18n

As you seen in previous sections, the helper method link_to_add_association treats the first parameter as a name. Additionally, if it's skipped and the form object is passed as the first one, then Cocoon names it using I18n.
It allows to invoke helper methods like this:

I18n
前のセクションで見たように、ヘルパー・メソッド link_to_add_association は、最初のパラメータを名前として扱う。さらに、それがスキップされ、フォーム・オブジェクトが最初に渡された場合、CocoonはI18nを使ってそれを命名する。

これにより、次のようにヘルパー・メソッドを呼び出すことができる。


= link_to_add_association form_object, :tasks
= link_to_remove_association form_object

instead of:

= link_to_add_association "Add task", form_object, :tasks
= link_to_remove_association "remove task", form_object
Cocoon uses the name of association as a translations scope key. If custom translations for association is not present it fallbacks to default name. Example of translations tree:

Cocoonは、Associationの名前をトランスレーション・スコープ・キーとして使用する。associationのカスタム・トランスレーションが存在しない場合は、デフォルトの名前にフォールバックする。トランスレーション・ツリーの例。

en:
 cocoon:
   defaults:
     add: "Add record"
     remove: "Remove record"
   tasks:
     add: "Add new task"
     remove: "Remove old task"
Note that link_to_remove_association does not require association name as an argument. In order to get correct translation key, Cocoon tableizes class name of the target object of form builder (form_object.object from previous example).

なお、link_to_remove_associationは、引数としてアソシエーション名を必要としない。正しい翻訳キーを得るために、Cocoonはフォーム・ビルダーのターゲット・オブジェクトのクラス名をテーブル化する(前の例ではform_object.object)。

Todo

add more sample relations: has_many :through, belongs_to, ...
improve the tests (test the javascript too)(if anybody wants to lend a hand ...?)

Todo
サンプル関係の追加: has_many :through, belongs_to, ...
テストの改善(javascriptのテストも)(誰か手を貸してくれないかな?)

公式ドキュメントのリンク

使用したツール

DeepL翻訳

 最後に
私がブログを書く目的は、素晴らしい本や、素晴らしい方々の技術記事を知って頂きたいからです。ぜひ、上記の参考文献を見て下さい。(noteなので広告とかは一切ありません。)

現在、株式会社grabssに行くために最後の悪あがきをしています!!
現在の進行状況
この記事は44件目の投稿。目標まで後6件。

よろしければ、スキボタン及びサポートお願いします。勉強の励みになります。

この記事が気に入ったらサポートをしてみませんか?