LoginSignup
35
20

More than 5 years have passed since last update.

Rails autosaveオプションの検証記録

Last updated at Posted at 2015-10-26

はじめに

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

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

サンプル

モデル

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

app/models/customer.rb
class Customer < ActiveRecord::Base
  has_one :address, dependent: :destroy

  validates :name, presence: true
end
app/models/address.rb
class Address < ActiveRecord::Base
  belongs_to :customer

  validates :address, presece: true
end

フォーム

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

app/forms/customer_form.rb
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

ビュー

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

app/views/customers/new.html.erb
<% @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>
app/views/customers/edit.html.erb
<% @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>
app/views/customers/_form.html.erb
<fieldset id="customer-fields">
  <legend>基本情報</legend>
  <%= render 'customer_fields', f: f %>
</fieldset>
<fieldset id="address-fields">
  <legend>自宅住所</legend>
  <%= render 'address_fields', f: f %>
</fieldset>
app/views/customers/_customer_fields.html.erb
<%= f.fields_for :customer, f.object.customer do |ff| %>
<div>
  <%= ff.label :name, '氏名', class: 'required' %>
  <%= ff.text_field :name, required: true %>
</div> 
app/views/customers/_address_fields.html.erb
<%= f.fields_for :address, f.object.customer.address do |ff| %>
<div>
  <%= ff.label :address, '住所', class: 'required' %>
  <%= ff.text_field :address, required: true %>
</div>

コントローラ

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

app/controllers/customers_controller.rb
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で指定した場合の検証です。

app/models/customer.rb
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で指定した場合の検証です。

app/models/customer.rb
class Customer < ActiveRecord::Base
  has_one :address, dependent: :destroy, autosave: false

  validates :name, presence: true
end
  • 新規登録の場合: Customerオブジェクトのみデータベースに保存され、Addressオブジェクトはデータベース保存されない。
  • 更新の場合: Customerオブジェクトの変更のみデータベースに保存され、Addressオブジェクトの変更はデータベースに保存されない。
35
20
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
35
20