Rails 4 & Devise - User's name is not added to database when new user created

7sunami picture 7sunami · Jul 16, 2013 · Viewed 7.7k times · Source

I'm new to the Ruby on Rails environment and most problems I've been able to solve, but I haven't been able to find a solution to this problem yet.

To provide context:

  • Using rails (4.0.0)
  • Using warden (1.2.3)
  • Using devise (3.0.0)
  • Using rolify (3.2.0)
  • Using cancan (1.6.10)

My Problem

When I sign_up a new user with Devise's registration. The :name field is not being added to the database. See server output

User model (app/models/user.rb)

:name is included in attr_accessible.

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

  # Setup accessible (or protected) attributes for your model
  attr_accessible :role_ids, :as => :admin
  attr_accessible :name, :email, :password, :password_confirmation, :remember_me

end

User controller (app/controllers/users_controller.rb).

I've added the params whitelist in order to keep with Rails 4, but this didn't solve the problem.

class UsersController < ApplicationController
  before_filter :authenticate_user!

  def index
    authorize! :index, @user, :message => 'Not authorized as an administrator.'
    @users = User.all
  end

  def show
    @user = User.find(params[:id])
  end

  def update
    authorize! :update, @user, :message => 'Not authorized as an administrator.'
    @user = User.find(params[:id])
    if @user.update_attributes(params[:user], :as => :admin)
      redirect_to users_path, :notice => "User updated."
    else
      redirect_to users_path, :alert => "Unable to update user."
    end
  end

  def destroy
    authorize! :destroy, @user, :message => 'Not authorized as an administrator.'
    user = User.find(params[:id])
    unless user == current_user
      user.destroy
      redirect_to users_path, :notice => "User deleted."
    else
      redirect_to users_path, :notice => "Can't delete yourself."
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_user
      @user = User.find(params[:id])
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def user_params
      params.require(:user).permit(:name, :email, :password, :password_confirmation, :remember_me)
    end
end

Devise's new registration view (app/views/devise/registrations/new.html.erb)

<h2>Sign up</h2>
<%= simple_form_for(resource, :as => resource_name, :url => registration_path(resource_name), :html => {:class => 'form-vertical' }) do |f| %>
  <%= f.error_notification %>
  <%= display_base_errors resource %>
  <%= f.input :name, :autofocus => true %>
  <%= f.input :email, :required => true %>
  <%= f.input :password, :required => true %>
  <%= f.input :password_confirmation, :required => true %>
  <%= f.button :submit, 'Sign up', :class => 'btn-primary' %>
<% end %>
<%= render "devise/shared/links" %>

Application controller (app/controllers/application_controller.rb)

I've followed the instructions with regard to strong parameters, and have included the lazy man's approach from Devise

class ApplicationController < ActionController::Base
  # Prevent CSRF attacks by raising an exception.
  # For APIs, you may want to use :null_session instead.
  protect_from_forgery with: :exception
  before_filter :configure_permitted_parameters, if: :devise_controller?

  rescue_from CanCan::AccessDenied do |exception|
    redirect_to root_path, :alert => exception.message
  end

  protected

  def configure_permitted_parameters
    devise_parameter_sanitizer.for(:sign_in) { |u| u.permit(:name, :email) }
  end
end

The server output when creating a new user.

Started POST "/users" for 127.0.0.1 at 2013-07-16 15:31:20 +1000
Processing by Devise::RegistrationsController#create as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"TYp9xOgtdKJI62rUddU7EE1C7FDF5qnmWgGENluzaWk=", "user"=>{"name"=>"John Smith", "email"=>"[email protected]", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"}, "commit"=>"Sign up"}
Unpermitted parameters: name
   (0.1ms)  begin transaction
  User Exists (0.1ms)  SELECT 1 AS one FROM "users" WHERE "users"."email" = '[email protected]' LIMIT 1
Binary data inserted for `string` type on column `encrypted_password`
  SQL (0.3ms)  INSERT INTO "users" ("created_at", "email", "encrypted_password", "updated_at") VALUES (?, ?, ?, ?)  [["created_at", Tue, 16 Jul 2013 05:31:20 UTC +00:00], ["email", "[email protected]"], ["encrypted_password", "$2a$10$kMfZLiBm6md0zoWXd0esjO/IRHBC72444ABDKcXVhPa6mCco9pIJu"], ["updated_at", Tue, 16 Jul 2013 05:31:20 UTC +00:00]]
   (17.0ms)  commit transaction
   (0.1ms)  begin transaction
Binary data inserted for `string` type on column `last_sign_in_ip`
Binary data inserted for `string` type on column `current_sign_in_ip`
  SQL (0.4ms)  UPDATE "users" SET "last_sign_in_at" = ?, "current_sign_in_at" = ?, "last_sign_in_ip" = ?, "current_sign_in_ip" = ?, "sign_in_count" = ?, "updated_at" = ? WHERE "users"."id" = 3  [["last_sign_in_at", Tue, 16 Jul 2013 05:31:20 UTC +00:00], ["current_sign_in_at", Tue, 16 Jul 2013 05:31:20 UTC +00:00], ["last_sign_in_ip", "127.0.0.1"], ["current_sign_in_ip", "127.0.0.1"], ["sign_in_count", 1], ["updated_at", Tue, 16 Jul 2013 05:31:20 UTC +00:00]]
   (1.1ms)  commit transaction
Redirected to http://0.0.0.0:3000/
Completed 302 Found in 94ms (ActiveRecord: 19.0ms)

My Conclusion

After all this I believe the problem lies in Devise's registration_controller, but I'm not exactly sure how to go about accessing the controller and rectifying this, or if this is where the problem actually is. I'm hoping it is something simple and I've just overlooked it.

If anyone has run into this problem or can shine some light on the situation, it would be greatly appreciated.

Cheers.

Answer

Arsalan T picture Arsalan T · Jul 22, 2013

Rails 4 uses strong parameters.

You have to permit the parameters which you want to pass through controller to model. in other words direct association to attributes in model through params is now not allowed you have to specify if any parameter value is suppose to pass through controller to model.

You may found some help on this blog: http://edgeapi.rubyonrails.org/classes/ActionController/StrongParameters.html

or as if we consider your problem you can either override the SessionsController for devise or use

devise_parameter_sanitizer(:sign_up)

more help can be found here: https://github.com/plataformatec/devise#strong-parameters