Search code examples
ruby-on-railsruby-on-rails-3deviserails-geocoder

Rails - how to validate presence of attribute AFTER creation


In my devise sign-up page, I have implemented an IP tracking feature that, when a user signs up, sends the country the user comes from, in order to populate the newly created account's attribute user_country.

I'd like to know if it's possible to implement a sort of validation on -user_country the same way I do for other User attributes (email, password...) when the user is created, to implement a sort of validation on user_country to be sure it's not empty nor nil, i.e that a user must always have a country identified.

I can't use the classic way with validates :user_country, presence: true, because when the user is created the user_country is still not filled but WAITS that RegistrationController makes a call to geocoder this way => see the method on the bottom called 'after_sign_up_path_for'

/app/controllers/registrations_controller.rb

class RegistrationsController < Devise::RegistrationsController

  layout 'lightbox'

  def update     
    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)
  end
  private :resource_params

  protected
    def after_sign_up_path_for(resource)
      resource.update(user_country: set_location_by_ip_lookup.country) #use concerns/CountrySetter loaded by ApplicationController
      root_path
    end  

end

Is there a way to implement a sort of 'validate' in this kind of situation?


Solution

  • My understanding is you want a User model to validate user_country field but only during steps after the initial creation?

    class User
       validates_presence_of :user_country, on: :update
    end
    

    will only validate on update and not creation. See http://apidock.com/rails/ActiveRecord/Validations/ClassMethods/validates_presence_of for other options that you can add.

    But for your use case, it seems odd that you need to do this in the controller after signup. I think it makes more sense to always validate user_country then inject the attribute during User creation in the controller.