Skip to content

Instantly share code, notes, and snippets.

@seak0503
Created August 24, 2016 21:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save seak0503/73a3dfd24a67df02e3c541edcba1c21b to your computer and use it in GitHub Desktop.
Save seak0503/73a3dfd24a67df02e3c541edcba1c21b to your computer and use it in GitHub Desktop.
Rails autosaveオプションの検証記録

はじめに

モデル間をアソシエーションしている際、関連づけられているモデルオブジェクトを自動的に保存したり、保存しないようにするにはautosaveオプションを利用します。

このオプションの挙動について、下記のサンプルを用いて検証をしました。

サンプル

モデル

CustomerモデルとAddressモデルを1対1で関連づけしています。

class Customer < ActiveRecord::Base
  has_one :address, dependent: :destroy

  validates :name, presence: true
end
class Address < ActiveRecord::Base
  belongs_to :customer

  validates :address, presece: true
end

フォーム

関連づけられたモデルを一つの画面で登録したり、編集したりするため、フォームオブジェクトを作成します。

class CustomerForm
  include ActiveModel::Model

  attr_accessor :customer
  delegate :persisted?, to: :customer

  def initialize(customer = nil)
    @customer = customer
    @customer ||= Customer.new
    @customer.build_address unless @customer.address
  end

  def assign_attributes(params = {})
    @params = params

    customer.assign_attributes(customer_params)
    customer.address.assign_attributes(address_params)
  end

  def save
    customer.save
  end

  private
  def customer_params
    @params.require(:customer).permit(:name)
  end

  def address_params
    @params.require(:address).permit(:address)
  end
end

ビュー

パーシャルをつかってビューを作成します。

<% @title = '顧客の新規登録' %>
<h1><%= @title %></h1>

<div id="generic-form">
  <%= form_for @customer_form, as: 'form', url: :customers do |f| %>
    <%= render 'form', f: f %>
    <div class="buttons">
      <%= f.submit '登録' %>
      <%= link_to 'キャンセル', :customers %>
    </div>
  <% end %>
</div>
<% @title = '顧客アカウントの編集' %>
<h1><%= @title %></h1>

<div id="generic-form">
  <%= form_for @customer_form, as: 'form',
    url: [ @customer_form.customer ] do |f| %>
    <%= render 'form', f: f %>
    <div class="buttons">
      <%= f.submit '更新' %>
      <%= link_to 'キャンセル', :customers %>
    </div>
  <% end %>
</div>
<fieldset id="customer-fields">
  <legend>基本情報</legend>
  <%= render 'customer_fields', f: f %>
</fieldset>
<fieldset id="address-fields">
  <legend>自宅住所</legend>
  <%= render 'address_fields', f: f %>
</fieldset>
<%= f.fields_for :customer, f.object.customer do |ff| %>
<div>
  <%= ff.label :name, '氏名', class: 'required' %>
  <%= ff.text_field :name, required: true %>
</div> 
<%= f.fields_for :address, f.object.customer.address do |ff| %>
<div>
  <%= ff.label :address, '住所', class: 'required' %>
  <%= ff.text_field :address, required: true %>
</div>

コントローラ

新規登録と編集用のコントローラを作成します。

class CustomersController < ApplicationController
  def new
    @customer_form = CustomerForm.new
  end

  def edit
    @customer_form = CustomerForm.new(Customer.find(params[:id]))
  end

  def create
    @customer_form = CustomerForm.new
    @customer_form.assign_attributes(params[:form])
    if @customer_form.save
      flash.notice = '顧客を追加しました。'
      redirect_to action: 'index'
    else
      flash.now.alert = '入力に誤りがあります。'
      render action: 'new'
    end
  end

  def update
    @customer_form = CustomerForm.new(Customer.find(params[:id]))
    @customer_form.assign_attributes(params[:form])
    if @customer_form.save
      flash.notice = '顧客情報を更新しました。'
      redirect_to action: 'index'
    else
      flash.now.alert = '入力に誤りがあります。'
      render action: 'edit'
    end
  end
end

検証1(autosaveオプションなし)

モデルにautosaveオプションを利用しない場合(つまり上記サンプルの状態)の検証です。

  • 新規登録の場合: CustomerオブジェクトとAddressオブジェクトの両方がデータベースに保存される。
  • 更新の場合: Csutomerオブジェクトの変更のみデータベースに保存され、Addressオブジェクトの変更はデータベースに保存されない。

検証2(autosaveオプションにtrueを指定)

モデルにautosaveオプションをtrueで指定した場合の検証です。

class Customer < ActiveRecord::Base
  has_one :address, dependent: :destroy, autosave: true

  validates :name, presence: true
end
  • 新規登録の場合: CustomerオブジェクトとAddressオブジェクトの両方がデータベースに保存される。
  • 更新の場合: CustomerオブジェクトとAddressオブジェクトの両方の変更がデータベースに保存される。

検証3(autosaveオプションにfalseを指定)

モデルにautosaveオプションをfalseで指定した場合の検証です。

class Customer < ActiveRecord::Base
  has_one :address, dependent: :destroy, autosave: false

  validates :name, presence: true
end
  • 新規登録の場合: Customerオブジェクトのみデータベースに保存され、Addressオブジェクトはデータベース保存されない。
  • 更新の場合: Customerオブジェクトの変更のみデータベースに保存され、Addressオブジェクトの変更はデータベースに保存されない。
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment