In my small rails app I have a controller called say and two pages hello and goodbye in it. I installed devise in the app. Initially i was able to access the sing_in page as /users/sign_in and similarly for sign up. I was not able to sign out and due to not able to sign out i am not able to access sign up or sign in page again. Now I entered the following code int eh say/hello page
<h1>Say#hello</h1>
<% if user_signed_in? %>
Hey signed in as <%= current_user.email %>.Not you?
<%= link_to "Logout", destroy_user_session_path %>
<% else %>
Hey <%= link_to "Login", new_user_session_path %> or Hey <%= link_to "Logup", new_user_registration_path %>
<% end %>
</p>
This the routes page of the app.
Demo::Application.routes.draw do
devise_for :users
get "say/hello"
get "say/goodbye"
# The priority is based upon order of creation: first created -> highest priority.
# See how all your routes lay out with "rake routes".
# You can have the root of your site routed with "root"
root :to => "say#hello"
end
Whenever I access the say/hello page, this is the output i get
Links
Hey signed in as x#gmail.com.Not you? Logout
When I click logout. It says
No route matches [GET] "/users/sign_out"
When I directly access users/sign_in I get routed to the say/hello page.
What mistake am I doing? How should I sign_out?
I have also tried
destroy_user_session_path, :method => :delete
Hope this could help
Try this in your routes.rb
devise_for :users do get '/users/sign_out' => 'devise/sessions#destroy' end
Related
Working on versions:
Ruby: 3.0.2
Rails 6.1.4
I'm trying to put a button in my View template for "Users" that will set the :mod attribute to false, with the button just being "Demote User".
I had it working SOMEHOW using a helper method, demote_user, and some variation of
<% if logged_in? && current_user.admin? %>
<%= link_to "Demote User", user_path(#user), onclick: demote_user(#user), class: "btn btn-info" %>
<% end %>
I messed up however it was working when trying to move this method into a controller for best practice. I'm not sure what format worked out, but I've tried many such as
:onclick => demote_user(#user)
onclick: 'demote_user(#user)'
onclick=demote_user(#user)
onclick='demote_user(#user)
and etc. Somehow, it did eventually work but I busted it. Now, every time I load the User's page, it's just executing demote_user(#user) without even needing to click the button, so refreshing a User's page is demoting them.
I am now trying to do this properly by creating a demote method in the UserController, but I have NO IDEA how to make the route, or make it work properly. Up until now, all my routes have been working using resources, and the basic new, create, destroy, etc.
I've been trying many different routes, and view formatting, with no luck and usually ending up with just: Routing Error
No route matches [GET] "/demote.3"
I'd like to be able to avoid using the Javascript onClick functionality and do it properly with the controller even if I could remember how to make it work, but I think my route, or view page, or controller is incorrect. Here are the contents of each file:
Controller
def demote
byebug
#user = User.find(params[:id])
#user.mod = false
redirect_to user_path(#user)
end
View
div class="container text-center mt-4">
<% if logged_in? && current_user.admin? %>
<%= link_to "Demote User", demote_path(#user), class: "btn btn-info" %>
<% end %>
</div>
Routes
Rails.application.routes.draw do
root 'pages#home'
get 'about', to: 'pages#about'
resources :articles
get 'signup', to: 'users#new'
resources :users, except: [:new]
get 'login', to: 'sessions#new'
post 'login', to: 'sessions#create'
delete 'logout', to: 'sessions#destroy'
resources :categories
post 'demote', to: 'users#demote'
end
Up until now, I've been following a course, and I've nailed everything in it and have added some of my own functionality, but I'm still not quite sure how to make sense of routes, or what paths it creates.
I'd like to make other similar custom controller functions beyond show, index, create, delete, update which are all I really understand how to build. I'm not even sure if POST is the correct call in the route.
I would just setup an additional RESTful action for the resource:
resources :users do
patch :demote
end
<% if logged_in? && current_user.admin? %>
<%= button_to "Demote User", demote_user_path(#user), method: :patch %>
<% end %>
You can use link_to instead of button_to but you need to use the correct method: :patch or data: { turbo_method: :patch } option depending on your version of Rails to get the javascript driver to do its trickery.
It is nice when I directly open 'http://localhost:3000/country.html' or click 'Country' button on navigation bar. But if I click 'Login'/'Signup'(http://localhost:3000/users/signin.html) first and then click 'Country' button, the url link to 'http://localhost:3000/users/country.html'. It shows 'No Route matches [GET] "/users/maison.html"'. Even more, the colour of 'Login' changes to a strange red which is similar to the default red '404' page in public.
Could anybody tell me why different clicking sequences will lead to different urls and how can I figure out the issue? Thanks!
This is an app based on Ruby on Rail, with devise, ruby-2.3.7,'rails', '~> 5.2.2' and mysql. I am using macOS Mojave.
'''
'application.html.erb':
<div class="outside_container">
<div class="main_container">
<div class="navbar clearfix">
<div class="container">
<ul class="nav left">
<li>Introduction</li>
<li>Country</li>
<li>Maison</li>
</ul>
<% if notice %>
<p class="notification"><%= notice %></p>
<% end %>
<% if alert %>
<p class="notification"><%= alert %></p>
<% end %>
<ul>
<p class="nav right">
<% if user_signed_in? %>
<%= link_to "Edit profile", edit_user_registration_path %> |
<%= link_to "Logout", destroy_user_session_path, method: :delete %> |
<% else %>
<%= link_to "Sign up", new_user_registration_path %> |
<%= link_to "Login", new_user_session_path %> |
<% end %>
</p>
</ul>
</div>
</div>
'''
sorry for missing route.rb, here it is:
'route.rb':
Rails.application.routes.draw do
devise_for :users
#make sure devise/session/new, which means the login page is the root page
devise_scope :user do
authenticated :user do
root 'country#index', as: :authenticated_root
end
unauthenticated do
root 'devise/sessions#new', as: :unauthenticated_root
end
end
get '/country', to: 'country#index'
get '/maison', to: 'maison#index'
# The priority is based upon order of creation: first created -> highest priority.
# See how all your routes lay out with "rake routes".
# You can have the root of your site routed with "root"
#root 'page#welcome'
resources :country
resources :maison
resources :introduction
resources :dashboard
end
So it looks like you have an href <li>Maison</li> that is pointing to /maison which means somewhere in your routes.rb there needs to be a route defined that matches that, as well as a controller that the route interfaces with:
get '/maison', to: 'home#index`
In the above route, we're saying "any get request to the /maison address should trigger the index method in the home_controller file in Rails.
Once you set the route and controller correctly, this should work properly.
There are a couple things:
The file should be titled routes.rb (plural)
So change route.rb to routes.rb.
Use the command $rails routes or $rake routes
To get a list of all routes you currently have available to you. If nothing shows, then rails is not recognizing your routes.
Use "Link To" for example
<%= link_to user.title, users_path(user) %>
Remove the dot from your URLs. The dot makes it a relative path, so wherever you are in your app, it will use that path as the starting point for those links. If you remove the period, it will always use your root path to build the links.
<li>Introduction</li>
<li>Country</li>
<li>Maison</li>
Really new to devise - it's very frustrating in all honesty...
My user session isn't being destroyed.
Here is the link in my navbar:
<li><%= link_to 'Logout', destroy_user_session_path, :method => :delete %></li>
devise.rb has the :delete method configured:
# The default HTTP method used to sign out a resource. Default is :delete.
config.sign_out_via = :delete
Route is:
destroy_user_session DELETE /users/sign_out(.:format) sessions#destroy
Application controller says :
class ApplicationController < ActionController::Base
protect_from_forgery
private
def after_sign_out_path_for(resource_or_scope)
root_path
end
I click my sign out link and my console shows :
Started GET "/users/sign_out" for 127.0.0.1 at 2014-04-18 12:00:26 -0500
Processing by UsersController#show as HTML
Parameters: {"id"=>"sign_out"}
MONGODB (0.8ms) waittext_development['users'].find({:_id=>BSON::ObjectId('53515685963e6507ad00003e')}).limit(-1)
It doesn't seem to be finding an active session (I've clicked it a dozen times in frustration), but the problem is the page I land out - UsersController#show - is not the page I've told it to route to. It should be the root_path which is users#index
So I was getting all these nil class errors on users#show because it was trying to render the default rails #user.name, etc. and #user isn't defined - I finally manually overrode the show action to simply render 'index' and I end up on my index page - BUT STILL - I'm seeing current_user.email printed here:
<% if user_signed_in? -%>
<ul>
<li><%= current_user.email %></li>
<li><%= link_to 'My info', edit_user_registration_path %></li>
<li><%= link_to 'Sign out', destroy_user_session_path %></li>
</ul>
It is evaluating TRUE and I'm getting those three list items.
User should not be signed in because I just destroyed the session!
What the heck?
You issue a GET request, not a DELETE (or even a POST with a set _method parameter to emulate a proper DELETE). As such, your request is routed to UsersController#show which listens to GET /users/:id.
The reason for that is, that a plain HTML link normally can only lead to GET requests. For anything else, you need a form. If you now pass the :method parameter to the link_to method in your view, Rails will generate some Javascript which captures the click on the link to generate a form and send the request that way. This will fail if the user has Javascript disabled, which seems to be the case here.
You should thus either ensure that all users (including you) have Javascript enabled or use something like button_to instead which will create a proper form in HTML which works without Javascript.
This is how i have implemented this so known to work:
devise_scope :user do
match "sign_out", :to => "sessions#destroy", via: [:delete]
end
<%= link_to sign_out_path, :method => "DELETE" do %>
<% end%>
I have a rails 3 app, and when I click the link to my terms page, it routes to a completely different controller, than what the routes should use. Stranger still, the route works when I'm not logged in, and I'm using devise.
I get this error when clicking the link when I'm logged in.
No route matches {:action=>"edit", :controller=>"users", :id=>nil}
<%= link_to "Terms", terms_path %>
Routes (in the order they appear in routes.rb):
devise_for :users, :controllers => {:registrations => "registrations"}
resources :users do
member do
get :following, :followers
post :accept
end
end
match '/terms', to: 'static_pages#user_agreement'
Static Pages Controller
def user_agreement
end
Rake Routes
terms /terms(.:format) static_pages#user_agreement
This also happens for every other action that I've routed this way to the staticpages controller, but not for any other actions that route to different controller.
Update: Terms Page
Header:
<%= link_to "Follow", users_path %>
<%= link_to current_user.name, current_user %>
<%= link_to "Sign out", destroy_user_session_path, :method => :delete %>
Footer:
<%= link_to "Welcome", welcome_path %>
<%= link_to "Settings", edit_user_path(#user) %>
<%= link_to "Terms", terms_path %>
All the content is pure html.
Thanks in advance
You have a link to edit_user_path with no #user as hinted in the comments.
You should almost certainly be using current_user anyway.
I have a very basic sign up and log in setup running and all I want to know if how to add a link at the very top of my root page that displays 'Log in' or 'Sign out' depending on whether the user is logged in or not.
I have tried various methods I have found on here but can't seem to get them to work as they often create undefined method errors.
What is the simplest way to create this?
Many thanks in advance for your help.
Tom
if you have a session variable where you save the id of the current user (i call it user_id) you could do it like this:
<% if session[:user_id] %>
<!-- user is logged in -->
<%= link_to logout_path %>
<% else %>
<!-- user is not logged in -->
<%= link_to login_path %>
<% end %>
that is what you have to change:
config/routes.rb:
resources :users
# login stuff
controller :sessions do
get "login" => "sessions#new"
post "login" => "sessions#create"
delete "logout" => "sessions#destroy"
end
app/views/sessions/new.html.erb:
# replace this line
<%= form_tag new_session_path do %>
# with
<%= form_tag login_path do %>
the login link is now:
<%= link_to "Login", login_path %>
the logout link:
<%= link_to "Logout", logout_path, :method => :delete %>
Not much of an answer but this Railscast was very helpful to me in learning about how authentication works in rails. The Railscast is Twitter login specific using OmniAuth but the process is much the same. He includes the dynamic links you asked about in his code.
http://railscasts.com/episodes/241-simple-omniauth