質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.53%

Railsでフォームに入力した値を保存できない理由がわからないので教えていただけないでしょうか?

解決済

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 212

koume

score 175

Rails5.1.3でWebアプリケーション制作の勉強をしています。
名前。メール、パスワード、電話番号、住所を入力し保存したいのですが、controllerのcreateメソッドで保存できず困っております。エラーも出ないしコードの見直しをしましたが自力で解決できないので教えていただけないでしょうか?。コードは以下になります。

visitor/new.html.erb

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

<div id="generic-form">
  <%= form_for @customer_form, as: 'form', url: :visitor_customers do |f| %>
    <%= render 'form', f: f %>
    <div class="buttons">
      <%= f.submit '登録' %>
      <%= link_to 'キャンセル', :visitor_customers %>
    </div>
  <% end %>
</div>
customers/_form.html.erb

<%= FormPresenter.new(f, self).notes %>

<fieldset id="customer-fields">
  <legend>基本情報登録(<strong>パスワードは記録、保管願います。</strong></legend>
  <%= render 'customer_fields', f: f %>
</fieldset>
<div>
  <strong><%= f.check_box :inputs_home_address %>
    <%= f.label :inputs_home_address, '← ☑ のまま自宅住所を入力してください。' %></strong>
</div>
<fieldset id="home-address-fields">
  <legend>自宅住所登録</legend>
  <%= render 'home_address_fields', f: f %>
</fieldset>
customers/_customer_fields.html.erb

<%= f.fields_for :customer, f.object.customer do |ff| %>
  <%= markup do |m|
    p = CustomerFormPresenter.new(ff, self)
    p.with_options(required: true) do |q|
      m << q.text_field_block(:email, 'メールアドレス', size: 32)
      m << q.password_field_block(:password, 'パスワード', size: 32)
      m << q.full_name_block(:family_name, :given_name, '氏名')
      m << q.full_name_block(:family_name_kana, :given_name_kana, 'フリガナ')
    end
    m.div(class: 'input-block') do
      m << p.decorated_label(:personal_phones, '電話番号')
      m.ol do
        p.object.personal_phones.each_with_index do |phone, index|
          m << render('phone_fields', f: ff, phone: phone, index: index)
        end
      end
    end
  end %>
<% end %>
customers/_phone_fields.html.erb

<%= f.fields_for :phones, phone, index: index do |ff| %>
  <%= markup(:li) do |m|
    m << ff.text_field(:number)
    m << ff.check_box(:primary)
    m << ff.label(:primary, '優先')
  end %>
<% end %>
customers/_home_address_fields.html.erb

<%= f.fields_for :home_address, f.object.customer.home_address do |ff| %>
  <%= markup do |m|
    p = AddressFormPresenter.new(ff, self)
    p.with_options(required: true) do |q|
      m << q.postal_code_block(:postal_code, '郵便番号', size: 7)
      m << q.drop_down_list_block(:prefecture, '都道府県', Address::PREFECTURE_NAMES)
      m << q.text_field_block(:city, '市区町村', SIZE: 16)
      m << q.text_field_block(:address1, '町域、番地等', size: 40)
    end
    m << p.text_field_block(:address2, '建物名、部屋番号等', size: 40)

  end %>
<% end %>
visitor/customers_controller.rb

class Visitor::CustomersController < Visitor::Base
  def new
    @customer_form = Visitor::CustomerForm.new
  end

  def create
    @customer_form = Visitor::CustomerForm.new
    @customer_form.assign_attributes(params[:form])
    if @customer_form.save
      flash.notice = '顧客アカウントを新規登録しました。'
      render action: 'new'
    else
      flash.now.alert = '入力に誤りがあります。'
      render action: 'new'
    end
  end

  private
  def customer_params
    @params.require(:customer).permit(:email, :password, :family_name, :given_name, :family_name_kana, :given_name_kana)
  end
end
visitou/customer_form.rb

class Visitor::CustomerForm
  include ActiveModel::Model

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

  def initialize(customer = nil)
    @customer = customer
    @customer ||= Customer.new(family_name_kana: 'カタカナ', given_name_kana: 'カタカナ')
    (2 - @customer.personal_phones.size).times do
      @customer.personal_phones.build
    end
    self.inputs_home_address = @customer.home_address.blank?
    @customer.build_home_address unless @customer.home_address
    @customer.build_history unless @customer.history_ids
  end

  def assign_attributes(params = {})
    @params = params
    self.inputs_home_address = params[:inputs_home_address] == '1'

    customer.assign_attributes(customer_params)

    phones = phone_params(:customer).fetch(:phones)
    customer.personal_phones.size.times do |index|
      attributes = phones[index.to_s]
      if attributes && attributes[:number].present?
        customer.personal_phones[index].assign_attributes(attributes)
      else
        customer.personal_phones[index].mark_for_destruction
      end
    end

    if inputs_home_address
      customer.home_address.assign_attributes(home_address_params)
    else
      customer.home_address.mark_for_destruction
    end
  end

  private
  def phone_params(record_name)
    @params.require(record_name).permit(phones: [ :number, :primary ])
  end

  def customer_params
    @params.require(:customer).permit(:email, :password, :family_name, :given_name, :family_name_kana, :given_name_kana)
  end

  def home_address_params
    @params.require(:home_address).permit(:postal_code, :prefecture, :city, :address1, :address2
    )
  end
end
presenters/form_presenter.rb

class FormPresenter
  include HtmlBuilder

  attr_reader :form_builder, :view_context
  delegate :label, :text_field, :password_field, :check_box, :radio_button, :text_area, :object, to: :form_builder

  def initialize(form_builder, view_context)
    @form_builder = form_builder
    @view_context = view_context
  end

  def notes
    markup(:div, class: 'notes') do |m|
      m.span '*', class: 'mark'
      m.text '印の付いた項目は入力必須です。'
    end
  end

  def text_field_block(name, label_text, options = {})
    markup(:div, class: 'input-block') do |m|
      m << decorated_label(name, label_text, options)
      m << text_field(name, options)
      m << error_messages_for(name)
    end
  end

  def password_field_block(name, label_text, options = {})
    markup(:div, class: 'input-block') do |m|
      m << decorated_label(name, label_text, options)
      m << password_field(name, options)
      m << error_messages_for(name)
    end
  end

  def date_field_block(name, label_text, options = {})
    markup(:div, class: 'input-block') do |m|
      m << decorated_label(name, label_text, options)
      if options[:class].kind_of?(String)
        classes = options[:class].strip.split + [ 'datepicker' ]
        options[:class] = classes.uniq.join(' ')
      else
        options[:class] = 'datepicker'
      end
      m << text_field(name, options)
      m << error_messages_for(name)
    end
  end

  def error_messages_for(name)
    markup do |m|
      object.errors.full_messages_for(name).each do |message|
        m.div(class: 'error-message') do |m|
          m.text message
        end
      end
    end
  end

  def decorated_label(name,label_text, options = {})
    label(name, label_text, class: options[:required] ? 'required' : nil)
  end

  def drop_down_list_block(name, label_text, choices, options = {})
    markup(:div, class: 'input-block') do |m|
      m << decorated_label(name, label_text, options)
      m << form_builder.select(name, choices, options)
      m << error_messages_for(name)
    end
  end
end
presenter/user_form_presenter.rb

class UserFormPresenter < FormPresenter

  def full_name_block(name1, name2, label_text, options = {})
    markup(:div, class: 'input-block') do |m|
      m << decorated_label(name1, label_text, options)
      m << text_field(name1, options)
      m << text_field(name2, options)
      m << error_messages_for(name1)
      m << error_messages_for(name2)
    end
  end
end
presenters/customer_form_presenter.rb

class CustomerFormPresenter < UserFormPresenter
  def password_field_block(name, label_text, options = {})
    if object.new_record?
      super(name, label_text, options)
    else
      markup(:div, class: 'input-block') do |m|
        m << decorated_label(name, label_text, options.merge(required: false))
        m << password_field(name, options.merge(disabled: true))
        m.button('変更する', type: 'button', id: 'enable-password-field')
        m.button('変更しない', type: 'button', id: 'disable-password-field', style: 'display: none')
        m << error_messages_for(name)
      end
    end
  end
end
presenters/addrss_form_presenter.rb

class AddressFormPresenter < FormPresenter
  def postal_code_block(name, label_text, options)
    markup(:div, class: 'input-block') do |m|
      m << decorated_label(name, label_text, options)
      m << text_field(name, options)
      m.span '(7桁の半角英数字で入力してください。)', class: 'notes'
      m << error_messages_for(name)
    end
  end
end


現象
フォームに入力し「登録」をクリックするとcreateアクションの「入力に誤りがあります。」と表示されて保存に失敗してしまうのです。

どなたか解決策を教えていただけないでしょうか?宜しくお願いします。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

0

@customer_form.saveが失敗しているのでその原因を探るために、
@customer_form.save!にして、ログでエラー内容を確認してみましょう。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/09/21 13:27

    回答ありがとうございます。log/development.logを表示しましたが、力量不足でlog内容がわかりません。
    質問の記述量が多すぎて追記できなかったので別途質問することにしました。

    キャンセル

同じタグがついた質問を見る