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!
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