0
votes

I'm new to this community as a logged-in user, but was saved by you guys a couple of times already without signing in. A big thanks for that.

I'm also relatively new to Ruby-on-Rails.

I have been bugging for two days now intending to disable redirecting created by devise...

Basically, I have a home_page where is displayed a custom signup form, using form_for and devise as follows:

<div class="signup">
    <div>
      <h2>Create a new account</h2>
      <p>It's quick and easy.</p>
    </div>

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

      <div class="form-styling">
        <div>
          <%= f.text_field :first_name,
                          required: true,
                          autofocus: true,
                          placeholder: "First Name",
                          label: false,
                          autocomplete: "off" %>

          <%= f.text_field :family_name,
                          required: true,
                          placeholder: "Family Name",
                          label: false,
                          autocomplete: "off" %>
        </div>
        <div>
          <%= f.text_field :username,
                          required: true,
                          placeholder: "Username",
                          label: false,
                          autocomplete: "off" %>
          <%= f.email_field :email,
                           required: true,
                           placeholder: "Email",
                           label: false,
                           autocomplete: "off" %>
        </div>
        <div>
          <%= f.password_field :password,
                              required: true,
                              hint: ("#{@minimum_password_length} characters minimum" if @minimum_password_length),
                              placeholder: "Password",
                              label: false,
                              autocomplete: "new-password" %>
          <%= f.password_field :password_confirmation,
                              required: true,
                              placeholder: "Password Confirmation",
                              label: false,
                              autocomplete: "new-password" %>
        </div>
        <div>
          <%= f.text_field :address,
                          required: true,
                          placeholder: "Neighbourhood",
                          label: false,
                          autocomplete: "off" %>
        </div>
        <div class="bottom-signup">
          <div class="sign-up-btn">
            <%= f.submit "Sign up" %>
          </div>
          <%- if devise_mapping.omniauthable? %>
            <%- resource_class.omniauth_providers.each do |provider| %>
              <%= link_to "Sign up with #{OmniAuth::Utils.camelize(provider)}", omniauth_authorize_path(resource_name, provider) %>
            <% end %>
          <% end %>
        </div>
      </div>

    <% end %>
  </div>

This form functions perfectly as wanted, but if one of the params required by Devise is false (for example: password_confirmation != password), it redirects me to: http://localhost:3000/users instead of http://localhost:3000/ where I want the form to be displayed.

This is due to the Devise framework, I understand, but I can't seem to manage to find my way around it..

I've tried changing the Devise RegistrationsController as such:

class Users::RegistrationsController < Devise::RegistrationsController
  # before_action :configure_sign_up_params, only: [:create]
  # before_action :configure_account_update_params, only: [:update]

  # GET /resource/sign_up
  # def new
  #   super
  # end

  # POST /resource
  def create
    build_resource(sign_up_params)
    if resource.save
      redirect_to products_path
    else
      redirect_to root_path
    end
    yield resource if block_given?
    if resource.persisted?
      if resource.active_for_authentication?
        set_flash_message! :notice, :signed_up
        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}"
        expire_data_after_sign_in!
        respond_with resource, location: after_inactive_sign_up_path_for(resource)
       end
     else
      clean_up_passwords resource
      set_minimum_password_length
      respond_with redirect_to: root_path(resource),
                   notice: resource.errors['current_password'][0]
     end
  end

  # GET /resource/edit
  # def edit
  #   super
  # end

  # PUT /resource
  # def update
  #   super
  # end

  # DELETE /resource
  # def destroy
  #   super
  # end

  # GET /resource/cancel
  # Forces the session data which is usually expired after sign
  # in to be expired now. This is useful if the user wants to
  # cancel oauth signing in/up in the middle of the process,
  # removing all OAuth session data.
  # def cancel
  #   super
  # 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: [:attribute])
  # 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: [:attribute])
  # end

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

  # The path used after sign up for inactive accounts.
  # def after_inactive_sign_up_path_for(resource)
  #   super(resource)
  # end
end

This is my ApplicationController:

class ApplicationController < ActionController::Base
  before_action :authenticate_user!
  before_action :configure_permitted_parameters, if: :devise_controller?
  protect_from_forgery with: :exception
  include Pundit

  # Pundit: white-list approach.
  after_action :verify_authorized, except: :index, unless: :skip_pundit?
  after_action :verify_policy_scoped, only: :index, unless: :skip_pundit?

  # Uncomment when you *really understand* Pundit!
  # rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized
  # def user_not_authorized
  #   flash[:alert] = "You are not authorized to perform this action."
  #   redirect_to(root_path)
  # end

  private

  def skip_pundit?
    devise_controller? || params[:controller] =~ /(^(rails_)?admin)|(^pages$)/
  end

  def configure_permitted_parameters
    # For additional fields in app/views/devise/registrations/new.html.erb
    devise_parameter_sanitizer.permit(:sign_up, keys: [:first_name, :family_name, :username, :address])

    # For additional in app/views/devise/registrations/edit.html.erb
    devise_parameter_sanitizer.permit(:account_update, keys: [:username])
  end

  def after_sign_in_path_for(resource)
    return products_path
  end

  def after_sign_up_path_for(resource)
    return products_path
  end
end

These are my routes:

devise_scope :user do
    get "/sign_in" => "pages#home" # custom path to login/sign_in
    get "/sign_up" => "pages#home", as: "new_user_registration" # custom path to sign_up/registration
  end

  devise_for :users, controllers: {
    sessions: 'users/sessions',
    registrations: 'users/registrations'
  }

  root to: 'pages#home'

I'm going crazy with this thing, but I would really like to understand Devise..

Let me know if you need anything else.

Thanks in advance!

2

2 Answers

0
votes

In the method where you check if he is logged in, and when you get false add

Redirect_to login_page_path
0
votes

me again.

I have solved the problem with a friend of mine after quite a bit of hustle.

Here goes a path to take that enables to disable automatic redirection to the devise form and enable to set your own and remain on the root_path after sign_up failure:

1) Add these lines to your routes in order to override the direct call-back to the Devise generated forms and to custom your user journey.

 devise_for :users, controllers: {
    registrations: 'users/registrations'
  }

By doing so, you tell Rails that you are changing variables of the Devise Controller for Registrations.

2) In your controllers/users/registrations_controller.rb create a new method create.

def create
    build_resource(sign_up_params)
    resource.save
    yield resource if block_given?
    if resource.persisted?
      if resource.active_for_authentication?
        set_flash_message! :notice, :signed_up
        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}"
        expire_data_after_sign_in!
        respond_with resource, location: after_inactive_sign_up_path_for(resource)
      end
    else
      clean_up_passwords resource
      set_minimum_password_length
      render "pages/home"
    end
  end

What I did here was only to change the last parcel from:

else
      clean_up_passwords resource
      set_minimum_password_length
      respond_with resource, :location => after_sign_in_path_for(resource)
    end

to

else
      clean_up_passwords resource
      set_minimum_password_length
      render "pages/home"
    end

3) Then you have to create a new file in your lib folder named custom_failure.rb (anywhere in the lib folder works perfectly fine). In this file, add the following lines:

class CustomFailure < Devise::FailureApp
  def redirect_url
    '/'
  end

def route
  '/'
end

  # You need to override respond to eliminate recall
  def respond
    if http_auth?
      http_auth
    else
      redirect
    end
  end
end

Here you override respond to eliminate recall.

4) Then inside config/initializers/devise.rb you add these lines:

config.warden do |manager|
    manager.failure_app = CustomFailure
  end

Basically, here you tell devise to look at the custom_failure.rb file you just created in case of a failure.

5) Finally, in your config/application.rb add these lines to your module:

config.autoload_paths << Rails.root.join('lib')

Here you tell Rails to automatically load your 'lib' folder and all the files that are in them (this step is not mandatory for all users it seems, but my rails app did not already automatically load the 'lib' files).


I hope this helped some of you.

Enjoy your code.

Best, Ist