LoginSignup
10
9

More than 3 years have passed since last update.

【Rails6】cocoonを使った動的フォーム入力画面の作り方

Posted at

はじめに

本記事では、以下のような入力フォームを作成することをゴールとしています。
Image from Gyazo

概要

レシピとレシピに必要となる食材をまとめてDBに保存する機能の作成

テーブル構成

レシピとレシピの食材は親子関係であるため、以下のテーブル構成となります
親:レシピ( recipes )
子:レシピの食材( recipe_ingredients )
※ingredient_idはactivie_hashで実装します
Image from Gyazo

実装

以下の順に実施していきます。
1.jqueryの導入
2.cocoonの導入
3.モデルの作成
4.コントローラーの作成
5.ビューの作成

1.jqueryの導入

rails6でcocoonを使えるようにするために、jqueryをインストールします。

$ yarn add jquery 

config/webpack/environment.jsを編集します

config/webpack/environment.js
const { environment } = require('@rails/webpacker')

#追記ここから
const webpack = require('webpack')
environment.plugins.prepend('Provide',
    new webpack.ProvidePlugin({
        $: 'jquery/src/jquery',
        jQuery: 'jquery/src/jquery'
    })
)
#追記ここまで

module.exports = environment

2.cocoonの導入

gemの導入

Gemfile
gem 'cocoon'
$ bundle install

ライブラリの追加

$ yarn add github:nathanvda/cocoon#c24ba53

実行後、以下2点の項目をクリアできていればOKです。
・app/assets/javascripts/cocoon.jsが作成されている
・package.jsonに以下の記述が追加されている

package.json
"cocoon": "github:nathanvda/cocoon#c24ba53"

最後に、app/javascriptspacks/application.jsに以下の内容を追記

app/javascriptspacks/application.js
require('jquery')
import "cocoon";

3.モデルの作成

今回の実装内容と関係のない記述は省いております。

モデルの作成

$ rails g model Recipe
$ rails g model RecipeIngredient

マイグレーションファイルの編集

class CreateRecipes < ActiveRecord::Migration[6.0]
  def change
    create_table :recipes do |t|
      t.string     :name,     null: false
      t.timestamps
    end
  end
end
class CreateRecipeIngredients < ActiveRecord::Migration[6.0]
  def change
    create_table :recipe_ingredients do |t|
      t.references :recipe,            null: false, foreign_key: true
      t.integer    :ingredient_id,     null: false
      t.integer    :quantity,          null: false
      t.timestamps
    end
  end
end

マイグレーションの実行

$ rails db:migrate

アソシエーションの設定

recipe.rb
class Recipe < ApplicationRecord
  has_many :recipe_ingredients, dependent: :destroy
  accepts_nested_attributes_for :recipe_ingredients
end
recipe_ingredient.rb
class RecipeIngredient < ApplicationRecord
  belongs_to :recipe
end

accepts_nested_attributes_for

 指定したモデルのデータを配列としてパラメーターに含めることが出来ます。
 つまり、recipeとrecipe_ingredients両モデルのデータをまとめて保存できるようになります。

4.コントローラーの作成

コントローラーの作成

$ rails g controller recipes new create

コントローラーの内容を編集

recipes_controller.rb
class RecipesController < ApplicationController
  def new
    @recipe = Recipe.new
    @recipe_ingredients = @recipe.recipe_ingredients.build
  end

  def create
    @recipe = Recipe.new(recipe_params)
    if @recipe.save
      redirect_to root_path
    else
      render action: :new
    end
  end

  private

  def recipe_params
    params.require(:recipe).permit(:name, recipe_ingredients_attributes: [:id, :ingredient_id, :quantity, :_destroy])
  end
end

accepts_nested_attributes_forで指定したrecipe_ingredientモデルを、
paramsにrecipe_ingredients_attributes: []として、追加して送っています。

5.ビューの作成

モデルと同様に、今回の実装内容と関係のない記述は省いております。
※クラス名等も記述していないため、このコードのままではレイアウトは崩れます。

recipes/new.html.erb
<%= form_with model: @recipe, url: '/recipes', method: :post, local: true do |f| %>

  <!-- レシピ名 -->
  <%= f.text_area :name %>

  <!-- 食材入力フィールド -->
  <%= f.fields_for :recipe_ingredients do |t| %>
    <%= render "recipes/recipe_ingredient_fields", f: t %>
  <% end %>

  <!-- 食材追加ボタン -->
  <%= link_to_add_association "追加", f, :recipe_ingredients %>
<% end %>

fields_for

form_with内で異なるモデルを編集できるようになります。

recipes/_recipe_ingredient_fields.html.erb
<div class="nested-fields">
    <%= f.collection_select(:ingredient_id, {}, :id, :name, {}) %>
    <%= f.number_field :quantity %>
    <div></div>
    <%= link_to_remove_association "削除", f %>
</div>

nested-fieldsクラスが指定されたdivタグで囲んだ範囲が追加・削除する領域です。

レンダリングする部分テンプレート名には注意してください。
「_子モデル_fields.html.erb」でないとエラーとなります。

お疲れさまでした。
以上で、動的入力フォームが作成できるかと思います。

参考

Rails6でのcocoonの導入
ネストしたフォームを簡潔に実装できるcocoon gemをwebpack環境でセットアップする

動的入力フォームの作成について
【Rails】cocoonを用いて親子孫関係のテーブルに複数のデータを同時保存する方法

fields_forについて
fields_forの上手な使い方

10
9
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
10
9