I want to signout from a controller. My controller looks like
def update
if #attendance.update_attribute(:logout_at, Time.now.localtime)
redirect_to signout_path and return
end
end
And my routes looks like
devise_scope :employees do
get "signout" => "devise/sessions#destroy"
end
devise_for :employees, :controllers => { registrations: 'registrations' }
But It gives error
Unknown action
Could not find devise mapping for path "/signout". This may happen for
two reasons: 1) You forgot to wrap your route inside the scope block.
For example: devise_scope :user do get "/some/route" =>
"some_devise_controller" end 2) You are testing a Devise controller
bypassing the router. If so, you can explicitly tell Devise which
mapping to use: #request.env["devise.mapping"] =
Devise.mappings[:user]
How can I do that? Please Help me out.
Thanks in advance.
You are redirecting, which makes a GET request to devise#sessions#destroy, a route that doesn't exist. The signout route in Devise is a mapped to a DELETE request. Instead of redirecting you should directly call the sign_out method that Devise makes available to you. After that be sure to redirect the user somewhere, maybe the login page.
A side note, in Rails 4 you can call update(attribute: value) directly. You don't need to call return either.
def update
#attendance.update(logout_at: Time.now.localtime)
sign_out
redirect_to login_path
end
I removed the if statement that wrapped the update call. By using one you are implying that there maybe a reason the save will not happen because of validation error, for example, and you need to provide feedback to the user. But in this case it's more likely to be an exception since there is no data input by the user. You can handle that at the application level.
Related
Rails 6, Devise 4.7.3 I have a forgotten password template in my views as users/passwords/new.html.erb that renders fine, collects an email, and sends that back to the Application. I also have a nice view template at users/passwords/edit that I am expecting to render when the email is sent in. In my case however, the template comes from devise/passwords/edit.html.erb which is not the one that should render.
Why is the devise template rendering and not the one I am expecting to run?
My routes:
devise_scope :user do
get 'sign_in', to: 'users/sessions#new'
get 'sign_up', to: 'users/registrations#new'
get 'forgot_password', to: 'users/passwords#new'
get 'reset_password', to: 'users/passwords#edit'
end
In the end, all I had to do to get MY controllers working was to add the devise_for :users route to point to { passwords: 'users/passwords' }
Since the devise controller is handling the password change it renders the default devise views.
You can either update the devise views with your own design or create your own update_password method to overwrite the default one from devise.
You can read more on how to implement your own update password method here: https://github.com/heartcombo/devise/wiki/How-To:-Allow-users-to-edit-their-password
I have a simple Devise registration form with the validatable plugin. It mostly works as intended, if the user forgets to enter a first name it redirects them back with a red validation message.
The problem is it redirects to the same path a successful login would have the user go to (i.e. it redirects them to /user and not back to /user/sign_up). If the user then refreshes the page for whatever reason they get a No route matches [GET] "/user" error.
How can I force a redirect to go back to the original /user/sign_up route on a sign up failure? I know I can hack the create action in the registration controller but when I redirect to the proper route I lose the Devise validation messages.
Update
It appears the problem is the way Devise handles respond_with Rails 4 How Overwrite Devise Respond Path Upon Error. It looks like Devise tries to render a create template at /user but I still can't override it.
First you can create devise controllers using following command -
rails generate devise:controllers users
Then you have to modify your routes for devise
# config/routes.rb
Rails.application.routes.draw do
devise_for :users,
:skip => [:registrations]
devise_scope :user do
get "user/sign_up", to: "users/registrations#new", as: :new_user_registration
post "user/sign_up", to: "users/registrations#create", as: :user_registration
end
end
Hope it's work.
I setup Devise so I can write controller specs with this.
Then I setup Devise so users cannot delete their accounts.
Now I want to write a spec to make sure the controller is unable to call the destroy action on the Devise user. How do I write this?
In my controller the Devise part looks like this
devise_for :users, skip: :registrations do
resource :registration,
only: [:new, :create, :edit, :update],
path: 'users',
path_names: { new: 'sign_up' },
controller: 'devise/registrations',
as: :user_registration do
get :cancel
end
end
In my spec I'm trying to do the following but it doesn't work. I'm not even sure I'm writing it right. I think the page I'm trying to access is wrong.
describe UsersController do
login_user # from devise controller helper
it "does not allow deleting of user" do
get :users, :method => :delete
# assert here user was not deleted
end
end
I think what you really want to test is whether or not the route exists for the registrations#destroy action. If there is no route, then the action will not be called since it can't be routed to the controller.
For a destroy action, we need to try to route a DELETE action to the users path. so, something like this might do the trick:
{ :delete=> "/users" }.should_not be_routable
Test syntax pulled from a similar answer here:
Rails RSpec Routing: Testing actions in :except do NOT route
Your mixing your http verbs for one thing. You should be doing
delete :destroy, id: #user
Your going to have to get #user from somewhere, I have it set by controller macros personally.
Then you can either check the response header for unsuccessful, or more easily
#user.should exist
I would put the following in my controller spec when testing this kind of thing (although i'd use FactoryGirl to create my test user):
it "does not allow deletion of a user" do
user = User.create!([insert valid args here])
expect {
delete :destroy, id: user
}.not_to change(User, :count)
end
I want to redirect an inactive user to the registration path to collect some information. Here are two approaches I took but neither is working:
I overrode the devise after_sign_in_path method as follows (in application_controller.rb):
def after_sign_in_path_for(resource)
debugger
if(account_active)
return root_path;
else
return edit_user_registration_path(resource)
end
end
When I hooked the code upto debugger, I see that devise does call after_sign_in_path_for. Also, the correct url is being generated by this call:
(rdb:2) after_sign_in_path_for(resource)
"/users/edit.1"
However, when I look at the server logs, there is no attempt being made to redirect to "/users/edit.1" under any circumstances.
I have tried moving the above method to application_helper.rb, session_controller.rb (by extending Devise::SessionController) and session_helper.rb
The issue is that devise does call this method to retrieve the url but it never attempts the redirect. I checked the web server logs, and devise directly goes to the user_root url.
Here is the relevant devise configuration from routes.rb:
devise_for :users do
resource :registration,
only: [:new, :create, :edit, :update],
path: 'users',
path_names: { new: 'sign_up' },
controller: 'devise/registrations',
as: :user_registration do
get :cancel
end
root :to => "home#index"
end
match '/user' => "products#index", :as => 'user_root'
Any suggestions on what I should try?
Thanks,
Tabrez
Are you sure you want to redirect to /users/edit.1? Rails will pick that up as if you're trying to access the 1 mime-type instead of html.
The user registration path doesn't need an id, because it always belongs to the currently signed in user. This should be enough:
def after_sign_in_path_for(resource)
if account_active
root_path
else
edit_user_registration_path
end
end
Also, placing it in the ApplicationController is the right spot. If you have your own sessions controller, like Users::SessionsController, which inherits from Devise::SessionsController, than it can go in there too.
So either the account_active method doesn't do what you think it does, or you've screwed up the routes file. Try working with a more vanilla configuration in your routes to see if that is the case:
devise_for :users
PS. as a complete an utterly unrelated side note: please try to use Ruby coding conventions, like no semicolons when they're not needed, no parenthesis in if statements, 2-spaces indenting and no unneeded return statements.
This may not apply to you, but in my recent use of devise + active_admin, I ran into the same problems you are describing. I added the devise override while my development rails server was running, and assumed rails/devise would automatically pick up the method. Apparently not since the problem was solved when I restarted my server.
It seems that devise is cherry picking these methods off ApplicationController when it initializes, though I havent looked at the source.
Users can be edited from a normal resourceful URI like:
/users/1/edit
The issue is that in my application, the edit user page is the home page or root route.
# routes.rb
root :to => "users#edit"
So, I tried to set #user to the current user in the absence of params[:id].
# app/controllers/users_controller.rb
def edit
#user = (params[:id]) ? User.find_by_id(params[:id]) : #current_user
end
Unfortunately, I'm having trouble getting the form to point properly.
# app/views/shared/_manage_users.rb
<%= form_tag follow_user_path, :id => 'update-following-form' %>
I'm getting:
No route matches {:action=>"follow", :controller=>"users"}
follow is a member route of the user resource and has a corresponding controller method. If I access the page via the URI at the top of this question, /users/1/edit, everything works fine and no error is thrown.
I'm not sure whether I'm going about this completely the wrong way or if I'm just not using the right form helper or something silly. How can I fix this issue, or what steps can I follow to debug it?
A member route expects the member to be passed as an argument. You route is expecting a User, like so:
follow_user_path(#user)
in your routes do this
resource :user
instead of
resources :users
now the id param is notin the url. you just need to ensure the user is logged in
I think you need to actually define follow_user in your routes.rb.
Example:
post "user/follow" => "users#follow", :as => :follow_user