QA@IT

NoMethodError (undefined method `name' for nil:NilClass)

3883 PV

こんにちは。

以下の様なDeviseのジェネレータを用いて作成したモデルがあり、「:html => { :multipart => true }」オプションを追加したフォームからfile_field(icon)に画像ファイルを指定してcreateメソッドにsubmitしたところ、タイトルの「NoMethodError (undefined method `name' for nil:NilClass)」が発生しました。ただし、file_field(icon)に何も指定しないとicon以外は正しく保存されます。

db/schema.rb

ActiveRecord::Schema.define(version: 20141112025346) do
  create_table "users", force: true do |t|
    t.string   "name",                                      default: "", null: false
    t.binary   "icon",                   limit: 2147483647
    t.string   "email",                                     default: "", null: false
    t.string   "encrypted_password",                        default: "", null: false
    t.string   "reset_password_token"
    t.datetime "reset_password_sent_at"
    t.datetime "remember_created_at"
    t.integer  "sign_in_count",                             default: 0,  null: false
    t.datetime "current_sign_in_at"
    t.datetime "last_sign_in_at"
    t.string   "current_sign_in_ip"
    t.string   "last_sign_in_ip"
    t.datetime "created_at"
    t.datetime "updated_at"
  end
end

以下にMVCを示します。(関係のある部分のみ)

app/models/user.rb

class User < ActiveRecord::Base
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable, :omniauthable
end

app/views/users/registrations/new.html.erb

<h2>Sign up</h2>

<%= form_for(resource, as: resource_name, :html => { :multipart => true }, url: registration_path(resource_name)) do |f| %>
  <%= devise_error_messages! %>

  <div><%= f.label :name, "お名前" %><br />
    <%= f.text_field :name, autofocus: true %></div>

  <div><%= f.label :icon, "アイコン" %><br />
    <%= f.file_field :icon %></div>

  <div><%= f.label :email, "メールアドレス" %><br />
    <%= f.email_field :email %></div>

  <div><%= f.label :password, "パスワード" %><br />
    <%= f.password_field :password, autocomplete: "off" %></div>

  <div><%= f.label :password_confirmation, "パスワード(確認用)" %><br />
    <%= f.password_field :password_confirmation, autocomplete: "off" %></div>

  <div><%= f.submit "Sign up" %></div>
<% end %>

<%= render "users/shared/links" %>

app/controllers/users/registrations_controller.rb

class Users::RegistrationsController < Devise::RegistrationsController

  before_filter :configure_permitted_parameters

  def new
    super
  end

  def create
    super
  end

  protected
    def configure_permitted_parameters
      devise_parameter_sanitizer.for(:sign_up) { |u| u.permit(:icon, :name, :email, :password, :password_confirmation) }
    end

    def sign_up_params
       devise_parameter_sanitizer.sanitize(:sign_up)
    end

end

動作①
name・icon・email・password・password_confirmationを入力し、Sign upをクリックすると「undefined method `name' for nil:NilClass」と怒られます。
スクリーンショット 2014-11-16 0.34.08.png
スクリーンショット 2014-11-16 0.34.39.png

動作②
iconにはなにも指定しないでSign upをクリックするとicon以外はきちんと登録されます。
スクリーンショット 2014-11-16 0.37.28.png

 User.all
  User Load (0.4ms)  SELECT `users`.* FROM `users`
=> [#<User id: 3, name: "山田太郎", icon: nil, email: "yamada@example.com", encrypted_password: "$2a$10$gjpCKyJ/lrAnp.ZsC.HCb.mPWyRprQBfbZ5dYHEaSgq...", reset_password_token: nil, reset_password_sent_at: nil, remember_created_at: nil, sign_in_count: 1, current_sign_in_at: "2014-11-15 15:37:37", last_sign_in_at: "2014-11-15 15:37:37", current_sign_in_ip: "127.0.0.1", last_sign_in_ip: "127.0.0.1", created_at: "2014-11-15 15:37:37", updated_at: "2014-11-15 15:37:37">]

createメソッドには以下のパラメータが送信されています。

{"utf8"=>"✓",
 "authenticity_token"=>"pWAkwJoYBj05BzgSyB0K1ItGcVXE+VkoCtXLoTVPrjw=",
 "user"=>{"name"=>"山田太郎",
 "icon"=>#<ActionDispatch::Http::UploadedFile:0x007fbb02c09d00 @tempfile=#<Tempfile:/var/folders/9s/9qds0lbn6n52gbz8b7ykxpgr0000gn/T/RackMultipart20141115-2132-1mqosjq>,
 @original_filename="icon.jpg",
 @content_type="image/jpeg",
 @headers="Content-Disposition: form-data; name=\"user[icon]\"; filename=\"icon.jpg\"\r\nContent-Type: image/jpeg\r\n">,
 "email"=>"yamada@example.com",
 "password"=>"[FILTERED]",
 "password_confirmation"=>"[FILTERED]"},
 "commit"=>"Sign up"}

エラーが起きている場所を特定する為にDevise::RegistrationsControllerのcreateメソッド

  # POST /resource
  def create
    build_resource(sign_up_params)

    resource_saved = resource.save
    yield resource if block_given?
    if resource_saved
      if resource.active_for_authentication?
        set_flash_message :notice, :signed_up if is_flashing_format?
        sign_up(resource_name, resource)
        respond_with resource, location: after_sign_up_path_for(resource)
      else
        set_flash_message :notice, :"signed_up_but_#{resource.inactive_message}" if is_flashing_format?
        expire_data_after_sign_in!
        respond_with resource, location: after_inactive_sign_up_path_for(resource)
      end
    else
      clean_up_passwords resource
      @validatable = devise_mapping.validatable?
      if @validatable
        @minimum_password_length = resource_class.password_length.min
      end
      respond_with resource
    end
  end

をコピーして当てはめてみると

resource_saved = resource.save

でエラーが発生していました。
ここの手前のbuild_resource(sign_up_params)でresourceが作られていないのか?と思ったので次の様に中身を見てみるときちんとUserモデルが作成されていました。

    logger.debug "=-=-=-=-=-=-=-=-=-=-=-=-=-=-="
    logger.debug "=-=-=-=-=   する前   =-=-=-=-="
    logger.debug "=-=-=-=-=-=-=-=-=-=-=-=-=-=-="
    logger.debug resource.inspect

    build_resource(sign_up_params)

    logger.debug "=-=-=-=-=-=-=-=-=-=-=-=-=-=-="
    logger.debug "=-=-=-=-=   した前   =-=-=-=-="
    logger.debug "=-=-=-=-=-=-=-=-=-=-=-=-=-=-="
    logger.debug resource.inspect
    logger.debug "=-=-=-=-=-=-=-=-=-=-=-=-=-=-="
    logger.debug "=-=-=-=-=-=-=-=-=-=-=-=-=-=-="

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
=-=-=-=-=   する前   =-=-=-=-=
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
nil
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
=-=-=-=-=   した前   =-=-=-=-=
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
#<User id: nil, name: "山田太郎", icon: #<ActionDispatch::Http::UploadedFile:0x007fd9ee63fe00 @tempfile=#<Tempfile:/var/folders/9s/9qds0lbn6n52gbz8b7ykxpgr0000gn/T/RackMultipart20141116-5573-dj5hix>, @original_filename="icon.jpg", @content_type="image/jpeg", @headers="Content-Disposition: form-data; name=\"user[icon]\"; filename=\"icon.jpg\"\r\nContent-Type: image/jpeg\r\n">, email: "yamada@example.com", encrypted_password: "$2a$10$OEukJ2lZMoFv4/G7CnkZyu7m.Mi8ekH56q2b1B4UUjS...", reset_password_token: nil, reset_password_sent_at: nil, remember_created_at: nil, sign_in_count: 0, current_sign_in_at: nil, last_sign_in_at: nil, current_sign_in_ip: nil, last_sign_in_ip: nil, created_at: nil, updated_at: nil>
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

なにかアドバイスを頂けたらと思います。よろしくお願いします。

ウォッチ

この質問への回答やコメントをメールでお知らせします。