Devise and Ruby on Rails: On Sign Up All Validations fail with "Can't be Blank"

Viewed 271

I am trying to sign up an Affiliate using Devise.

/affiliates/registrations_controller.rb

class Affiliates::RegistrationsController < 
    Devise::RegistrationsController
    include StatesHelper, ApplicationHelper

    before_action :configure_sign_up_params, only: [:create]
    before_action :configure_account_update_params, only: [:update]

    # GET /resource/sign_up
    def new
        @plan = AffiliatePlan.find_by(nickname: params.permit(:plan)[:plan].downcase)
        super
    end

    # GET /resource/edit
    def edit
        @states = us_states
        super
    end

    # PUT /resource
    def update
        @states = us_states
        super
        if resource.address_coordinates.length > 1 
            resource.services.each{ |s| s.update_attributes( {lonlat: "POINT(#{resource.address_coordinates.join(' ')})"})}
        end 
    end

    def update_resource(resource, params)
        resource.update_without_password(params)
    end

    protected

    # If you have extra params to permit, append them to the sanitizer.
    def configure_sign_up_params
        devise_parameter_sanitizer.permit(:sign_up, keys: [:business_name, :website, :phone, :affiliate_plan_id, contact_name: [:first_name, :last_name], address: [:street_address, :address_line2, :city, :state, :zip_code]])
    end

    # If you have extra params to permit, append them to the sanitizer.
    def configure_account_update_params
        devise_parameter_sanitizer.permit(:account_update, keys: [:business_name, :website, :phone, :affiliate_plan_id, contact_name: [:first_name, :last_name], address: [:street_address, :address_line2, :city, :state, :zip_code]])
    end

    # The path used after sign up.
    def after_sign_up_path_for(resource)
        affiliate_signups_path
    end
end

/affiliates/registrations/new.html.erb

<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>

    <%= devise_error_messages! %>

    <% if @plan %>
        <%= f.hidden_field :affiliate_plan_id, value: @plan.id %>
    <% else %>
        <%= f.hidden_field :affiliate_plan_id, value: resource.affiliate_plan_id %>
    <% end %>

    <%= f.fields_for :contact_name do |n| %>

        <%= n.text_field :first_name, autofocus: true, placeholder: "First Name*", class: "form-control", required: true %>

        <%= n.text_field :last_name, placeholder: "Last Name*", class: "form-control", required: true  %>
     <% end %>

    <%= f.text_field :business_name, placeholder: "Company Name", class: "form-control" %>

    <%= f.email_field :email, autocomplete: "email", placeholder: "Email Address*", class: "form-control", required: true %>

    <%= f.password_field :password, autocomplete: "new-password", placeholder: "Create a Password", class: "form-control", required: true %>

    <%= f.password_field :password_confirmation, autocomplete: "new-password", placeholder: "Confirm Password", class: "form-control", required: true %>


    <%= f.submit "Next", class: "btn btn-primary btn-sm" %>
<% end %>

routes.rb

devise_for :affiliates, path: "partners", controllers: {
  sessions: 'affiliates/sessions',
  registrations: 'affiliates/registrations'
}

When submitting the form I always get validation errors:

7 errors must be fixed
   - Email can't be blank
   - Password can't be blank
   - Password is too short (minimum is 9 characters)
   - Password must contain at least one digit
   - Password must contain at least one punctuation mark or symbol
   - Password must contain at least one upper-case letter
   - Affiliate plan must exist

The log shows an immediate rollback, but no other information:

Started POST "/partners" for 127.0.0.1 at 2020-05-25 14:09:59 -0400
Processing by Affiliates::RegistrationsController#create as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"SowYVWzTqVYdwZWjYjNc3hlGC5UITqt+bKjQuSATOpLcdVGb52x7gEi8p15MmhlZrLNLpD07fCxp5Gya8/cQMg==", "affiliate"=>{"affiliate_plan_id"=>"2", "contact_name"=>{"first_name"=>"Stephen", "last_name"=>"Tilly"}, "business_name"=>"1995", "email"=>"sarwerera@email.com", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"}, "commit"=>"Next"}
(0.2ms)  BEGIN
  ↳ app/controllers/affiliates/registrations_controller.rb:18
   (0.2ms)  ROLLBACK
  ↳ app/controllers/affiliates/registrations_controller.rb:18
  Rendering affiliates/registrations/new.html.erb within layouts/application
  Rendered affiliates/registrations/new.html.erb within layouts/application (2.6ms)

I'm not quite sure where to go from there, any ideas?

2 Answers

I'll assume you have another Devise resource setup which is why you've created this setup. I'll assume it's User. In that case one of the main reasons could be that Devise is expecting that model as the resource which is why it's throwing erros about missing validations. Since Devise::RegistrationsController is expecting a params[:user] containing the e-mail and password.

Suggestion: If that's the case I would consider associating the Affiliate profile to the existing resource and go on from there. I.e. Affiliate -> belongs:to -> User. It would make your life easier.

I think this may work.

We assume that an Affiliate does not have a plan, because he has not yet registered. The Plan must exist!

In the file new.html.erb it is not recommended to use logic, if you want, you can do it in the controller. Sample: before_action :set_plan, only: [:new]

class Affiliates::RegistrationsController < Devise::RegistrationsController
  include StateHelper, ApplicationHelper

  before_action :set_plan, only: [:new]
  before_action :configure_permitted_parameters, only: [:create]

  protected
    def set_plan
      @plan = AffiliatePlan.find_by(nickname: params[:plan])
    end

  def configure_permitted_parameters
    devise_parameter_sanitizer.permit(:sign_up) do |user_params|
      user_params.permit([
        :email, :password, :password_confirmation,
        :business_name, :website, :phone, :affiliate_plan_id,
        contact_name: [:first_name, :last_name],
        address: [:street_address, :address_line2, :city, :state, :zip_code]
      ])
    end
  end
end

On the other hand, it would be great if you separated the extra information of the Affiliate from the information of the Affiliate as a user.

Example:

For the User:

Affiliate data is: email, password, password_confirmation, username, etc

For the extra info of Affiliate:

Affiliate Info data is: :business_name, :website, :phone, etc

Related