My custom Devise Sessions controller isn't letting me sign in. I've had several difficulties trying to customize the Devise controllers, but I can't figure out what's going on here.
When I try to sign in, the page (sessions#new) simply re-renders. How can I get my custom controller back to full functionality?
# controllers/sessions_controller
class SessionsController < Devise::SessionsController
skip_before_filter :store_last_attempted_location
skip_after_filter :store_last_successful_location
def new
super
end
def create
super
end
def destroy
super
end
end
My routes
#config/routes.rb
devise_for :users, :controllers => { :sessions => "sessions", :registrations => "registrations" }
Thanks in advance.
If the sign in page is re-rendered after entering the user credentials then it means that the credentials are invalid which is resulting in the re-rendering. But that should have resulted in a flash message on the re-rendered page as Devise uses flash messages to let the application users know if sign in was successful or failure.
Make sure that you are displaying flash messages in application.html.erb as:
<% flash.each do |name, msg| %>
<%= content_tag :div, msg %>
<% end %>
Related
When Devise user signs up, I need to redirect him to a view where he can select what kind of user he wants to be, like:
link_to 'TypeA', new_type_a_path.
link_to 'TypeB', new_type_b_path.
link_to 'TypeC', new_type_c_path.
How to configure tis route? I know I can use:
class Users::RegistrationsController < Devise::RegistrationsController
protected
def after_sign_up_path_for(resource)
signed_in_root_path(resource)
end
But its been a while I worked with RoR, so dont remember - should I create a controller just for this view?
You can create a view, where you place your three links in order the user can choose.
The after_sign_up_path_for helper method allows you to specify an URI or a route prefix, so you can create an entry for that view and use it in that method, like:
# views/registrations/choices.html.erb
<%= link_to 'TypeA', new_type_a_path %>
<%= link_to 'TypeB', new_type_b_path %>
<%= link_to 'TypeC', new_type_c_path %>
# config/routes.rb
get 'choose', to: 'registrations_controller#choices', as: :choices
# registrations_controller.rb
def after_sign_up_path_for(resource)
choices_path
end
I have Devise and OmniAuth-Twitter setup. I used to use email signup with Devise, then I switched to Twitter login. Now I need to disable email sign up and sign in access for everyone.
http://localhost:3000/register
http://localhost:3000/login
I tried the code below in views, but I get error. I assume because of it being an ActiveRecord feature.
redirect_to root_path
and I couldn't redirect in Controller as before_action: since I do not have controller for Devise.
What is best way to disable access to this register and login pages?
Thank you!
If you really want to redirect from the login and registration pages, you should create two controllers that extend Devise::SessionsController and Devise::RegistrationsController and then configure your routes to use your controllers instead of the default controllers that Devise uses.
Here's an example for the login path only, but it's the same logic for registrations.
# config/routes.rb
devise_for :users, controllers: { sessions: 'users/sessions' }
# app/controllers/users/sessions_controller.rb
module Users
class SessionsController < Devise::SessionsController
def new
# Redirect wherever you want here
redirect_to root_path
end
end
end
Please note that devise allows you to skip some routes as well, but keep in mind that the whole controller will be excluded, which might not be what you want.
# config/routes.rb
devise_for :users, only: [:passwords]
# or
devise_for :users, skip: [:sessions]
It's not necessarily that you need controller logic, it's that you need to block that ability from the view side. You have appname/app/views/devise/registrations/new.html.erb and appname/app/views/devise/sessions/new.html.erb that you need to modify to remove the form fields that you want to hide and also delete stuff from your appname/app/views/devise/shared/_links.html.erb as well to disallow the signup there too.
You're going to want to delete the code that looks like lines 8-10 and lines 12-14 in your shared _links.html.erb file.
1 <%- if devise_mapping.omniauthable? %>
2 <%- resource_class.omniauth_providers.each do |provider| %>
3 <div class="twitter-button">
4 <%= link_to "Sign in with #{OmniAuth::Utils.camelize(provider)}", omniauth_authorize_path(resource_name, provider), class: "twitter-text" %>
5 </div>
6 <% end -%>
7 <% end -%>
8 <%- if controller_name != 'sessions' && false %>
9 <%= link_to "Log in", new_session_path(resource_name), class: "forget" %>
10 <% end -%>
11
12 <%- if devise_mapping.registerable? && controller_name != 'registrations' && false %>
13 <%= link_to "Sign up", new_registration_path(resource_name), class: "forget" %>
14 <% end -%>
But, at the end of the day I don't think it's necessarily a great idea to completely disallow people that don't have a twitter to utilize your app, because it greatly reduces the number of people that can now use your app right off the bat.
Is it possible limit the number of emials sent for devise recoverable in a period of time for each user? How can I defend against malicious requests?
I would use grecaptcha to protect your form where you let the user rescue his account.
It's really easy and simple to use and include it in your rails app.
In your view:
<%= form_for #user do |f| %>
<%= recaptcha_tags %>
<% end %>
In your controller, create action:
def create
verify_recaptcha(model: #user) # => returns true or false
end
To limit: "emials sent for devise recoverable"
Example Gemfile:
gem 'simple_captcha2'
routes:
devise_for :users, :controllers => { ..., :passwords => 'passwords', ... }
app/controllers/passwords_controller.rb:
class PasswordsController < Devise::PasswordsController
prepend_before_action :require_no_authentication
#
# GET /resource/password/new
def create
if simple_captcha_valid?
super
else
....
end
end
end
app/views/devise/passwords/new.html.erb
into the form_for:
<%= show_simple_captcha %>
I would like to know how I would take the user's input and use it to redirect them to a new URL. For example if the user entered "556859" into the input field and clicked "Go" it would take them to www.website.com/556859.
I'm using ruby on rails but am not sure how to achieve my goal. Any input would be appreciated.
If you need examples for the view and the rest as well, then ask. But this controller method should be enough to point you in the right direction:
def redirect_action
redirect_to "/#{params[:redirect_path]}"
end
You can send user input to controller method
and in that method you can use redirect_to helper method
For example
in view create form with action="controller/redirect"
and in controller create method redirect
and with params[] use your input
Best regards
You'd do something like this:
#app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
def redirect
redirect_to root_path + param
end
end
#config/routes.rb
post "", to: "application#redirect", as: :redirect
#app/views/application/index.html.erb
<%= form_tag redirect_path do %>
<%= f.input :param %>
<%= f.submit "Go" %>
<% end %>
--
The next question becomes "why?"
Rails' routing infrastructure is such that it should give you the ability to access individual views for what you're trying to accomplish.
For example, if you're trying to show users in that redirect, you can do:
#config/routes.rb
resources :users
#app/controllers/users_controller.rb
class UsersController < ActionController::Base
def show
#user = User.find params[:id]
end
end
This will give you the ability to access http://yoururl.com/users/12312321
Alternatively, you could also (if you had nothing else on that part of the app), do the following:
#config/routes.rb
resources :users, path: "" #-> http://yoururl.com/12313123
If you know what type of data you're trying to show, it should give us more to work with in regards how you'd construct routing structure for it.
I'm trying to make it so only admins can add uses with devise. I've gotten it mostly working however now when I'm logged in as an admin and submit the sign up form it kicks me back with the error: You are already signed in.
I've tried to follow the instructions here: http://wiki.summercode.com/rails_authentication_with_devise_and_cancan but it doesn't seem to mention this situation.
Do I need to do further overriding in the editors_controller to allow this?
Here are my routes ("editors" is the name of my user model):
devise_for :admins, :skip => [:registrations]
as :admin do
get 'admin/editors' => 'editors#index', as: :admin_editors
get 'admin/editors/new' => 'editors#new', as: :new_editor
delete 'admin/editors/:id' => 'editors#destroy', as: :destroy_editor
end
devise_for :editors, :skip => [:registrations], :controllers => { :registrations => "editors" }
and my editors_controller in "app/controllers/"
class EditorsController < Devise::RegistrationsController
before_filter :check_permissions, :only => [:new, :create, :cancel]
skip_before_filter :require_no_authentication
def dashboard
render "editors/dashboard.html.haml"
end
def index
#editors = Editor.all
respond_to do |format|
format.html
end
end
private
def check_permissions
authorize! :create, resource
end
end
EDIT
I noticed this Processing by Devise::RegistrationsController#create as HTML in the logs when I submit the form. I had suspected that perhaps the skip_before_filter :require_no_authentication wasn't being called, but assumed that because the EditorsController was inheriting from RegistrationController that before filter would work properly. Is that not the case?
You'll want to implement your own create method on EditorsController instead of inheriting that action from Devise::RegistrationsController. As you're seeing, the method in Devise::RegistrationsController will first check to see if you're already logged in and kick you back if you are. If you're not logged in it will create a User account and then log you in as that user.
You're trying to get around that problem with skip_before_filter :require_no_authentication, but it's likely that your form is POSTing to /editors instead of /admin/editors. So, you'll need to add a route that allows you to get to create on the EditorsController :
as :admin do
post 'admin/editors' => 'editors#create'
# your other :admin routes here
end
Then you'd want to implement a scaled down version of create. You probably want something kind of like this :
class EditorsController < Devise::RegistrationsController
def create
build_resource(sign_up_params)
if resource.save
redirect_to admin_editors_path
else
clean_up_passwords resource
respond_with resource
end
end
# your other methods here
end
You'll also want to make sure that the admin/editors/new template is pointing the form to the correct route ('admin/editors').
None of the googleable solutions worked when I tried them. This works
What I did was create a new action in the controller and a new route for it, and connect the links on my views that normally connect to create to now call my route and action.
But that wasn't enough. Because Devise is listening and will grab any add you try to do and validate it through it's own code. So instead I just add the new user record with a sql insert.
Add this route
post 'savenew', to: 'users#savenew'
Add this action to the user controller:
def savenew
rawsql = "insert into users (email, created_at,updated_at) values ('#{user_params[:email]}',now(), now())"
sql = rawsql
ActiveRecord::Base.connection.execute(sql)
redirect_to action: 'index''
end
View: new.html.erb
change the form_for so that submit will go to the new route and action, not the default Rails one.
<%= form_for User, :url => {:action => "savenew"} do |f| %>
Using Rails 4.2.6 here (my model is User instead of Editor). The following solution bypasses (I think) any devise actions that may interfere with new User creation by the admin:
Add this action to the Users controller:
def savenew
User.create_new_user(user_params)
redirect_to action: 'index'
end
Add this private method to the Users controller if it does not exist:
private
def user_params
params.require(:user).permit(:email, :password,
:password_confirmation)
end
Add this to config/routes.rb:
match '/savenew', to: 'users#savenew', via: :post
Add this class method to the User model:
def self.create_new_user(params)
#user = User.create!(params)
end
I don't have a separate Admin class in my application. Instead, I defined an admin attribute for Users and check for it with a :validate_admin before_action filter in the UsersController.
I wanted to be able to create a new user from the :index view, so I added a button:
<%= button_to 'New User', '/new_user', class: 'btn btn-primary',
method: :get %>
You might have to tweak the above solution if you have any after_create actions in the User model (e.g. sending a welcome email).