Ruby on Rails - submodel, subclass or subcontroller 만들기(references type)

우선 기준이 스케폴드로 CRUD 모델을 하나 만들어줍니다.

#> rails new log
#> cd log
#> rails g scaffold rule name:string desc:text

이 모델 아래 복수의 데이터를 가지는 모델을 만들어봅시다.

하위에 포함될 모델 만들기, 라우팅 설정

#> rails g model pattern data:text rule:references

여기서 references 타입은 FK를 만들어준다고 생각하면 좋습니다. pattern이라는 모델을 만들면서 data라는 text 타입의 속성과 rule을 참조하는 references 타입의 속성을 만들었습니다.

rule 하위에서 patterns이 라우팅되도록 routes.rb를 수정해줍니다.

#> vim config/routes.rb
Rails.application.routes.draw do
  resources :rules do
  resources :patterns
  end
end

제 어플리케이션은 rule이 다수의 pattern을 가져야 하기 떄문에 model에 has_many로 pattern을 여러개를 가질 수 있도록 수정해줍니다.

#> vim app/model/rule.rb
class Rule < ActiveRecord::Base
has_many :patterns
end

컨트롤러 설정하기

이제 pattern을 만드는 메소드를 만들어봅시다. pattern의 컨트롤러를 아래와 같이 수정합니다. (

#> vim app/controllers/patterns_controller.rb
class PatternsController < ApplicationController
        def create
                @rule = Rule.find(params[:rule_id])               # 현재 Rule의 번호를 찾고
                @pattern = @rule.patterns.create(pattern_params)  # 인자값(이 어플에선 data)를 가지고 pattern을 생성합니다.
                redirect_to rule_path(@rule)                      # 다되면 rule page로 이동
        end

        private                                                   # rails4 버전 이후부터, 파라미터에 대해서 제한하는 설정이 기본으로 필요합니다.
        def pattern_params                                        # 안하면 아래 에러가 나요.
                params.require(:pattern).permit!
        end
end

만약 pattern_params 처럼 허용 파라미터를 정의하지 않고 직접 파라미터 값을 받아서 쓰면

###

ActiveModel::ForbiddenAttributesError

에러가 발생합니다. 이유인 즉슨, Rails 4 버전대 이후부터 정책적으로 파라미터 제한을 기본으로 설정하도록 되어서 그렇습니다.

처음에 튜토리얼 코드에서 많이 낚이죠..

View 수정을 통해 추가 페이지 보여주기

마지막으로 view에 하위 모델인 pattern을 추가할 수 있도록 UI를 구성해줍니다.

#> vim app/views/rules/show.html.erb
<p id="notice"><%= notice %></p>

<p>
  <strong>Name:</strong>
  <%= @rule.name %>
</p>

<p>
  <strong>Desc:</strong>
  <%= @rule.desc %>
</p>
<strong>Pattern</strong>
<% @rule.patterns.each do |patt| %>
<p> - <%= patt.data %> </p>

<% end %>

Add
<%= form_for([@rule, @rule.patterns.build]) do |f| %>
<div class="field"><%= f.label :data %><br>
                           <%= f.text_field :data %>
</div>
<div class="actions"><%= f.submit %></div>
<% end %>

<%= link_to 'Edit', edit_rule_path(@rule) %> |
<%= link_to 'Back', rules_path %>