【Rails6】cocoon을 사용한 동적 폼 입력 화면을 만드는 방법

12061 단어 Rails6루비Rails

소개



이 기사에서는 다음과 같은 입력 양식을 작성하는 것을 목표로합니다.


개요



레시피와 레시피에 필요한 재료를 함께 DB에 저장하는 기능 만들기

테이블 구성



레시피와 레시피의 재료는 부모와 자식 관계이므로 다음과 같은 테이블 구성입니다.
부모: 레시피( recipes )
아이 : 레시피 재료 ( recipe_ingredients )
※ingredient_id는 active_hash로 구현합니다.


구현



다음 순서로 실시합니다.
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를 잘 사용하는 방법

좋은 웹페이지 즐겨찾기