Unable to change the custom field for users (account update) in my Rails 4 with Currency application (Rails 4, currency 3, formtastic, geocoder)

advertisements

I'm geolocating the user with geocoder and storing the value I get in the User's table (in a attribute called user_country_name).

I am sure it has nothing to do with geocoder but I don't manage to simply edit the country in User Account page.

I tried to edit the email and the passwoird and it works but not the other custom fields i added compared to Devise basic form.

I think I've done all needed to update account attributes in Rails 4 but keep getting this error for 2 whole days!

ActionController::UnpermittedParameters at /
found unpermitted parameters: user_country_name

  1. Here is my form for User info edit

       <%= semantic_form_for(resource, :as => resource_name, :url => registration_path(resource_name), :html => { :method => :put, :class => 'form-vertical' }) do |f| %>
    
              <%= f.semantic_errors %>
    
                <%= f.inputs do %>
                  <%= f.input :email, :required => true %>   
    
                  <%= f.input :user_country_name,
                    :as         => :select,
                    :collection => COUNTRIES, # sends to a constant I have with all countries
                    :prompt     => true
                  %> 
    
                  <%= f.input :password, :input_html => { :autocomplete => "off" }, :hint => t("devise.registrations.edit_account_page.leave_blank_if_dont_want_to_change"), :required => false %>
                  <%= f.input :password_confirmation, :required => false %>
                <% end %>
    
                <%= f.actions do %>
                  <div>
                    <%= f.action :submit, :label => t("devise.registrations.edit_account_page.update"), :button_html => { :class => 'btn-primary' } %>
                  </div>
                  <div class="half-right-small return-login">
                  <%= link_to t("directions.back"), :back %>
                  </div>
    
               <% end %>
    
            <% end %>
    
    
  2. here is my application controller

    class ApplicationController < ActionController::Base
    
      protect_from_forgery
    
      include CountrySetter # handle localization through ip lookup and the I18n used
      include LocaleSetter
    
      # handle Cancan authorization exception
      rescue_from CanCan::AccessDenied do |exception|
        exception.default_message = t("errors.application_controller_exception_messages.only_open_to_admin")
        if current_user # if it's user redirect to main HP
          redirect_to root_path,              :alert => exception.message
        else
          redirect_to customerinterface_path, :alert=> exception.message
        end
      end  
    
      before_filter :configure_permitted_parameters, if: :devise_controller?  
    
      private      
    
        before_filter :authenticate_user_from_token!
        before_filter :authenticate_customer_from_token!
    
        def authenticate_user_from_token!
          user_email = params[:user_email].presence
          user       = user_email && User.find_by_email(user_email)
    
          if user && Devise.secure_compare(user.authentication_token, params[:user_token])
            sign_in user, store: false  # we are signing in user if it exists. sign_in is devise method to sign in any user
            redirect_to root_path       # now we are redirecting the user to root_path i.e our homepage
          end
        end
    
      protected
    
       def configure_permitted_parameters
          [:sign_up, :account_update].each do |sanitize_me|
            devise_parameter_sanitizer.for(sanitize_me) do |u|
              u.permit(:email, :password, :password_confirmation, :user_country_name)
            end
          end
        end
    
        def devise_parameter_sanitizer
          if resource_class == User
            UserParameterSanitizer.new(User, :user, params)
          else # for customers
            CustomerParameterSanitizer.new(Customer, :customer, params)
          end
        end
    
    end
    
    
  3. and finally the RegistrationsController form Devise:

    class RegistrationsController < Devise::RegistrationsController
    
    def update
    
    # added for upgrade to Rails 4
    account_update_params = devise_parameter_sanitizer.sanitize(:account_update)
    
    # required for settings form to submit when password is left blank
    if account_update_params[:password].blank?
      account_update_params.delete("password")
      account_update_params.delete("password_confirmation")
    end
    
    @user = User.find(current_user.id)
    if @user.update(account_update_params) # Rails 4 .update introduced with same effect as .update_attributes
      set_flash_message :notice, :updated
      # Sign in the user bypassing validation in case his password changed
      sign_in @user, :bypass => true
      redirect_to after_update_path_for(@user)
    else
      render "edit"
    end
    end
    
    # for Rails 4 Strong Parameters
    def resource_params
      params.require(:user).permit(:email, :password, :password_confirmation, :current_password, :user_country_name)
    end
    private :resource_params
    
    # used to update user-country by ip lookup when user signs up and associate newly signed-up user with a country
    # source - stackoverflow.com/questions/24294169/devise-sign-up-how-to-save-an-attribute-without-having-a-form-field-for-it-ra
    protected
      def after_sign_up_path_for(resource)
        resource.update(user_country_name: set_country) #use concerns/CountrySetter loaded by ApplicationController
        root_path
      end
    
    end
    
    

EDIT

To answer some comments asking for the Route

MyApp::Application.routes.draw do

  # redundancy with below standard users 'root to' code. Goal: to easily be able to change
  # the page if decide one day that users should see a different page when they log in
  # used to be a bug- solved with: https://github.com/plataformatec/devise/issues/2393#issuecomment-17544388
  authenticated :user do
    root to: 'static_pages#home', as: :authenticated_root
  end

  # Homepage for unauthenticated users
  # used to be a bug- solved with: https://github.com/plataformatec/devise/issues/2393#issuecomment-17544388
  unauthenticated do
    root to: 'static_pages#home' # , as: :unauthenticated_root
  end

  # Routes for users
  devise_for  :users,
    :token_authentication_key => 'authentication_key',
    :controllers              =>  { confirmations:  'confirmations',
                                    registrations:  'registrations',
                                    sessions:       'sessions',
                                    passwords:      'passwords',
                                    unlocks:        'unlocks' },
    path: '', # inspired by Nitish solution to make devise urls custom (source: tackoverflow.com/questions/19889570/rails-devise-user-registration-route-post)
    path_names:   { :sign_in  => "signin",
                    :sign_out => "logout",
                    :sign_up  => "signup" }                   

  resources :users

  # Routes for customers
  devise_for :customers,
    controllers: {  registrations:  'customers/registrations', # inspired by stackoverflow.com/questions/20913157/devise-views-with-multiple-models
                    confirmations:  'customers/confirmations',
                    sessions:       'customers/sessions',
                    passwords:      'customers/passwords',
                    unlocks:        'customers/unlocks'  },
    path:         'advertiser', # inspired by Nitish solution to make devise urls custom (source: tackoverflow.com/questions/19889570/rails-devise-user-registration-route-post)
    path_names:   { :sign_in  => "signin",
                    :sign_out => "logout",
                    :sign_up  => "signup" }

  # Routes for the interface with reportings and private data for Customers
  # Customers interface HP can be accessed at /campaigns
  match '/customerinterface',
   to:    'clientreporting_pages#index',
   path:  'campaigns',
   via:   'get'                                

  # Routes for all managed by Active Admin (deals creation, prizes creation...)
  devise_for :admin_users, ActiveAdmin::Devise.config
  ActiveAdmin.routes(self)

  # Static Pages
  match '/help',            to: 'static_pages#help',          path: 'help',     via: 'get'
  match '/aboutus',         to: 'static_pages#aboutus',       path: 'about-us', via: 'get'
  match '/contact',         to: 'static_pages#contact',                         via: 'get'
  match '/howitworks',      to: 'static_pages#howitworks',    path: 'about',    via: 'get'
  match '/globalpresence',  to: 'static_pages#globalpresence',path: 'global',   via: 'get'

And here is the detailed log of error I get in my local console

Started PUT "/" for 127.0.0.1 at 2014-10-08 19:55:50 +0200
Processing by RegistrationsController#update as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"geygeyegyegyegyegeykd7NwrVyAw=", "user"=>{"email"=>"[email protected]", "user_country_name"=>"Germany", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"}, "commit"=>"<span class="}
  User Load (0.7ms)  SELECT "users".* FROM "users" WHERE "users"."id" = 457 ORDER BY "users"."id" ASC LIMIT 1
Completed 500 Internal Server Error in 7ms

ActionController::UnpermittedParameters - found unpermitted parameters: user_country_name:
  actionpack (4.0.5) lib/action_controller/metal/strong_parameters.rb:372:in `unpermitted_parameters!'
  actionpack (4.0.5) lib/action_controller/metal/strong_parameters.rb:270:in `permit'
  devise (3.2.4) lib/devise/parameter_sanitizer.rb:66:in `permit'
  devise (3.2.4) lib/devise/parameter_sanitizer.rb:58:in `account_update'
  devise (3.2.4) lib/devise/parameter_sanitizer.rb:77:in `default_sanitize'
  devise (3.2.4) lib/devise/parameter_sanitizer.rb:24:in `sanitize'
  app/controllers/registrations_controller.rb:11:in `update'
  actionpack (4.0.5) lib/action_controller/metal/implicit_render.rb:4:in `send_action'
  actionpack (4.0.5) lib/abstract_controller/base.rb:189:in `process_action'
  actionpack (4.0.5) lib/action_controller/metal/rendering.rb:10:in `process_action'
  actionpack (4.0.5) lib/abstract_controller/callbacks.rb:18:in `block in process_action'
  activesupport (4.0.5) lib/active_support/callbacks.rb:483:in `_run__3174996646979711185__process_action__callbacks'
  activesupport (4.0.5) lib/active_support/callbacks.rb:80:in `run_callbacks'
  actionpack (4.0.5) lib/abstract_controller/callbacks.rb:17:in `process_action'
  actionpack (4.0.5) lib/action_controller/metal/rescue.rb:29:in `process_action'
  actionpack (4.0.5) lib/action_controller/metal/instrumentation.rb:31:in `block in process_action'
  activesupport (4.0.5) lib/active_support/notifications.rb:159:in `block in instrument'
  activesupport (4.0.5) lib/active_support/notifications/instrumenter.rb:20:in `instrument'
  activesupport (4.0.5) lib/active_support/notifications.rb:159:in `instrument'
  actionpack (4.0.5) lib/action_controller/metal/instrumentation.rb:30:in `process_action'
  actionpack (4.0.5) lib/action_controller/metal/params_wrapper.rb:250:in `process_action'
  activerecord (4.0.5) lib/active_record/railties/controller_runtime.rb:18:in `process_action'
  actionpack (4.0.5) lib/abstract_controller/base.rb:136:in `process'
  actionpack (4.0.5) lib/abstract_controller/rendering.rb:44:in `process'
  actionpack (4.0.5) lib/action_controller/metal.rb:195:in `dispatch'
  actionpack (4.0.5) lib/action_controller/metal/rack_delegation.rb:13:in `dispatch'
  actionpack (4.0.5) lib/action_controller/metal.rb:231:in `block in action'
  actionpack (4.0.5) lib/action_dispatch/routing/route_set.rb:80:in `call'
  actionpack (4.0.5) lib/action_dispatch/routing/route_set.rb:80:in `dispatch'
  actionpack (4.0.5) lib/action_dispatch/routing/route_set.rb:48:in `call'
  actionpack (4.0.5) lib/action_dispatch/routing/mapper.rb:44:in `call'
  actionpack (4.0.5) lib/action_dispatch/journey/router.rb:71:in `block in call'
  actionpack (4.0.5) lib/action_dispatch/journey/router.rb:59:in `each'
  actionpack (4.0.5) lib/action_dispatch/journey/router.rb:59:in `call'
  actionpack (4.0.5) lib/action_dispatch/routing/route_set.rb:674:in `call'
  warden (1.2.3) lib/warden/manager.rb:35:in `block in call'
  warden (1.2.3) lib/warden/manager.rb:34:in `catch'
  warden (1.2.3) lib/warden/manager.rb:34:in `call'
  rack (1.5.2) lib/rack/etag.rb:23:in `call'
  rack (1.5.2) lib/rack/conditionalget.rb:35:in `call'
  rack (1.5.2) lib/rack/head.rb:11:in `call'
  actionpack (4.0.5) lib/action_dispatch/middleware/params_parser.rb:27:in `call'
  actionpack (4.0.5) lib/action_dispatch/middleware/flash.rb:241:in `call'
  rack (1.5.2) lib/rack/session/abstract/id.rb:225:in `context'
  rack (1.5.2) lib/rack/session/abstract/id.rb:220:in `call'
  actionpack (4.0.5) lib/action_dispatch/middleware/cookies.rb:486:in `call'
  activerecord (4.0.5) lib/active_record/query_cache.rb:36:in `call'
  activerecord (4.0.5) lib/active_record/connection_adapters/abstract/connection_pool.rb:626:in `call'
  activerecord (4.0.5) lib/active_record/migration.rb:373:in `call'
  actionpack (4.0.5) lib/action_dispatch/middleware/callbacks.rb:29:in `block in call'
  activesupport (4.0.5) lib/active_support/callbacks.rb:373:in `_run__2636980444171422651__call__callbacks'
  activesupport (4.0.5) lib/active_support/callbacks.rb:80:in `run_callbacks'
  actionpack (4.0.5) lib/action_dispatch/middleware/callbacks.rb:27:in `call'
  actionpack (4.0.5) lib/action_dispatch/middleware/reloader.rb:64:in `call'
  actionpack (4.0.5) lib/action_dispatch/middleware/remote_ip.rb:76:in `call'
  better_errors (1.1.0) lib/better_errors/middleware.rb:84:in `protected_app_call'
  better_errors (1.1.0) lib/better_errors/middleware.rb:79:in `better_errors_call'
  better_errors (1.1.0) lib/better_errors/middleware.rb:56:in `call'
  actionpack (4.0.5) lib/action_dispatch/middleware/debug_exceptions.rb:17:in `call'
  actionpack (4.0.5) lib/action_dispatch/middleware/show_exceptions.rb:30:in `call'
  railties (4.0.5) lib/rails/rack/logger.rb:38:in `call_app'
  railties (4.0.5) lib/rails/rack/logger.rb:20:in `block in call'
  activesupport (4.0.5) lib/active_support/tagged_logging.rb:68:in `block in tagged'
  activesupport (4.0.5) lib/active_support/tagged_logging.rb:26:in `tagged'
  activesupport (4.0.5) lib/active_support/tagged_logging.rb:68:in `tagged'
  railties (4.0.5) lib/rails/rack/logger.rb:20:in `call'
  quiet_assets (1.0.2) lib/quiet_assets.rb:18:in `call_with_quiet_assets'
  actionpack (4.0.5) lib/action_dispatch/middleware/request_id.rb:21:in `call'
  rack (1.5.2) lib/rack/methodoverride.rb:21:in `call'
  rack (1.5.2) lib/rack/runtime.rb:17:in `call'
  activesupport (4.0.5) lib/active_support/cache/strategy/local_cache.rb:83:in `call'
  rack (1.5.2) lib/rack/lock.rb:17:in `call'
  rack (1.5.2) lib/rack/sendfile.rb:112:in `call'
  railties (4.0.5) lib/rails/engine.rb:511:in `call'
  railties (4.0.5) lib/rails/application.rb:97:in `call'
  rack (1.5.2) lib/rack/lock.rb:17:in `call'
  rack (1.5.2) lib/rack/content_length.rb:14:in `call'
  rack (1.5.2) lib/rack/handler/webrick.rb:60:in `service'
  /home/me/.rvm/rubies/ruby-2.0.0-p451/lib/ruby/2.0.0/webrick/httpserver.rb:138:in `service'
  /home/me/.rvm/rubies/ruby-2.0.0-p451/lib/ruby/2.0.0/webrick/httpserver.rb:94:in `run'
  /home/me/.rvm/rubies/ruby-2.0.0-p451/lib/ruby/2.0.0/webrick/server.rb:295:in `block in start_thread'

EDIT #2

I tried everything that you guys proposed but nothing worked. then i tried one thing: I removed devise_parameter_sanitizer. then it works!! but should/can i remove this without compromising the security of the app? isn't this block important?

Here is the block I removed:

def devise_parameter_sanitizer
      if resource_class == User
        UserParameterSanitizer.new(User, :user, params)
      else # for customers
        CustomerParameterSanitizer.new(Customer, :customer, params)
      end
    end

What does it tell me about the problem ? maybe it's an important clue to the real bug but i don't get it:)

Many thanks for any help!


can you try this please

application controller

before_action :configure_permitted_parameters, if: :devise_controller?

and

application Controller

protected

def configure_permitted_parameters
  devise_parameter_sanitizer.for(:sign_up) << [your params]
  devise_parameter_sanitizer.for(:account_update) << [your params]
end

Registrations controller

<!-- REMOVE -->
# added for upgrade to Rails 4
account_update_params = devise_parameter_sanitizer.sanitize(:account_update)

# for Rails 4 Strong Parameters
def resource_params
  params.require(:user).permit(:email, :password, :password_confirmation, :current_password, :user_country_name)
end
private :resource_params

let me know how this works out for you, you seem to be declaring your permitted params too many times in different places