Rails Route adding dot with Devise - ruby-on-rails

My rails app is adding a dot/period "." into the route when trying to browse to a devise gem user's profile.
routes.rb:
devise_for :users, :controllers => { :registrations => "registrations" }
(Basically using routes to allow for some custom functions - it should be still using the default devise routing paths.
Rake routes output:
user_registration POST /users(.:format) registrations#create
new_user_registration GET /users/sign_up(.:format) registrations#new
edit_user_registration GET /users/edit(.:format) registrations#edit
Link in view:
<%= link_to 'Edit', edit_user_registration_path(user) %>
Where user is defined in a .each loop.
Outputted Link in URL looks like:
http://localhost:3000/users/edit.2
My goal is to have a link to edit any user's profile (permissions controlled outside these items of course).
I "think" my problem is the routes.rb and not specifying the path correctly there. I think it should be something that would have a rake routes that includes an :id parameter.
Thanks for the help!

That's normal routes's devise, registrations#edit is for edit current signed-in user, If you want to CRUD interface for users (I think you want to editing a user), you can add another controller (e.g users_controller.rb) and make some action , example for controller :
def edit
#user = User.find(params[:id])
end
def update
if params[:user][:password].blank?
params[:user].delete(:password)
params[:user].delete(:password_confirmation)
end
#user = User.find(params[:id])
respond_to do |format|
if #user.update_attributes(params[:user])
format.html { redirect_to some_path, notice: 'Updated.' }
format.json { head :no_content }
else
format.html {
flash[:alert] = "Something wrong"
render :action => :edituser
}
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
On your routes.rb you can following like this
scope '/user' do
match '/edit/:id' => 'users#edit', :as => :edit_user
put '/update/:id' => 'users#update', :as => :update_user
end
And links on each section looks like :
<%= link_to 'Edit', edit_user_path(user) %>
references :
How To: Manage users through a CRUD interface
CRUD Devise Example

I think Devise's edit_user_registration_path uses current_user internally, so you shouldn't need the (user) in your link_to

Related

Unable to find working route - No route matches {:action=>"show", :controller=>"users"}

No route matches {:action=>"show", :controller=>"users"}
Working with a condition current_page in rails with this format. Trying to not render a navbar within users/show path, but it should be visible in the rest of site. One thing to note is that the users/show URL has been configured in routes.rb to not show '/users/' folder in the URL, so it looks like 'mysite.com/username'
<% if current_page?(controller: 'users', action: 'show') %>
no navbar
<% else %>
<%= render partial: "shared/navbar" %>
<% end %>
The first condition works fine, however when I reach a page that should match the 'else' condition, for instance my root_path, I get this error:
ActionController::UrlGenerationError in Dashboard#show
Showing /Users/javier/Desktop/rails-apps/testtradus3/app/views/shared/_navbar.html.erb where line #1 raised:
No route matches {:action=>"show", :controller=>"users"}
My route.rb looks like this
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
Rails.application.routes.draw do
...
# This removes '/users/' from user/show URI
resources :users, path: '', :only => [:show]
# User account
devise_for :users,
controllers: {
omniauth_callbacks: "users/omniauth_callbacks",
registrations: "users/registrations",
sessions: "users/sessions"
}
devise_scope :user do
get "session/otp", to: "sessions#otp"
end
resources :users do
resources :builduser, controller: 'users/builduser'
end
...
end
This returns this rails routes:
users GET /users(.:format) users#index
POST /users(.:format) users#create
I have tried removing the custom path in routes.rb, so something like resources :users and that returns these routes
users GET /users(.:format) users#index
POST /users(.:format) users#create
GET /users(.:format) users#index
POST /users(.:format) users#create
GET /users/new(.:format) users#new
GET /users/:id/edit(.:format) users#edit
GET /users/:id(.:format) users#show
My UsersController.rb
class UsersController < ApplicationController
def index
#users = User.all
end
def show
#user = User.friendly.find(params[:id])
#order = Order.new
end
def create
#user = User.new(user_params)
respond_to do |format|
if #user.save
# format.html { redirect_to #order, notice: "Order was successfully created." }
# Added this one below:
format.html { redirect_to user_builduser_index_path(#user)}
format.json { render :show, status: :created, location: #user }
else
format.html { render :new, status: :unprocessable_entity }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
..
end
Going off some of the examples listed in the link below, you could try:
current_page?(users_path(current_user))
# or
current_page?(users_path(#user))
# or even
current_page?("/#{#user&.id}")
An alternative could be to set a before_action in your ApplicationController to set an instance variable:
before_action :display_nav_bar # this would apply to all routes unless overridden like below in the UsersController
def display_nav_bar
#display_nav_bar = true
end
# and in your UsersController:
def show
#display_nav_bar = false
# other stuff
#user = User.find(params[:id)
end
then
<% if #display_nav_bar %>
<%= render partial: "shared/navbar" %>
<% else %>
no navbar
<% end %>
You could also look into using layouts for different controllers and control rendering the nav bar that way.
current_page? source

Ruby on Rails: Adding Additional RESTFUL Actions

In my rails app I would like to have two patch methods for updating the users profile.
First, I will have an 'account_settings' GET request, which will use the standard edit/update REST action to update certain parameters. Then, I would like to have an additional 'edit_profile' and 'update_profile' actions to get a page that will allow the user to update different user attributes. Here's how it looks in my users_controller.rb for a better idea:
#For account settings page
#This is for the account settings page
#(only changing email and password)
def edit
#user = User.find(params[:id])
end
def update
#user = User.find(params[:id])
respond_to do |format|
if #user.update_attributes(account_settings_params)
flash.now[:success] = "Your settings have been successfully updated."
format.html {redirect_to #user}
else
format.html {redirect_to edit_user_path}
flash[:error] = "Please be sure to fill out your email, password, and password confirmation."
end
end
end
def edit_profile
#user = User.find(params[:id])
end
#For update profile
def update_profile
#user = User.find(params[:id])
respond_to do |format|
if #user.update_attributes(user_profile_params)
flash.now[:success] = "Your profile has been updated."
format.html {redirect_to #user}
else
format.html {redirect_to edit_profile_user_path}
flash[:error] = "Please be sure to fill out all the required profile form fields."
end
end
end
private
def account_settings_params
params.require(:user).permit(:email, :password, :password_confirmation)
end
def user_profile_params
params.require(:user).permit(:name, :about_me, :location, :image_url)
end
Selection from my current routes.rb :
#Account Settings Just for Email and Password
get 'account_settings' => 'users#edit'
patch 'settings' => 'users#update'
resources :users do
member do
get :edit_profile
put :update_profile
end
end
Results of rake routes:
edit_profile_user GET /users/:id/edit_profile(.:format) users#edit_profile
update_profile_user PATCH /users/:id/update_profile(.:format) users#update_profile
users GET /users(.:format) users#index
POST /users(.:format) users#create
new_user GET /users/new(.:format) users#new
edit_user GET /users/:id/edit(.:format) users#edit
user GET /users/:id(.:format) users#show
PATCH /users/:id(.:format) users#update
PUT /users/:id(.:format) users#update
DELETE /users/:id(.:format) users#destroy
My navbar partial:
-if logged_in?
-# Logged in links
%li
=link_to 'Logout', logout_path, method: :delete
%li
=link_to 'Account Settings',edit_user_path(#current_user)
%li
=link_to 'Edit My Profile', edit_profile_user_path(#current_user)
%li
=link_to 'View My Profile', user_path(#current_user)
%li
=link_to 'Members', users_path
On the edit_profile page, my form looks like this:
=form_for #user, path: update_profile_user_path(#user) do |f|
With my current implementation, visiting the edit_profile page and posting the form will lead back to the regular edit page with my rails server saying that the parameters were unpermitted. However, as you can see in my update_profile method in my controller, the controller method for update_profile accepts user_profile_params rather than the account_settings_params . Any insight onto why it might be doing this?
A few notes:
You don't need render "edit_profile" because that is done by default
You don't need to overwrite the edit route
I'd strongly suggest actually having a separate Profile controller, instead of trying to hack it in as extra actions on user.
That being said, the routes look like
resources :users do
member do
get :edit_profile
patch :update_profile
end
end
then your link would be to users/1/edit_profile (link_to "edit", edit_profile_path(#user)) and the form would be to <%= form_for #user, path: update_user_path(#user) %>
To add RESTful routes to the current resources you can use collection or members based on the requirement.
collection is used as a non membered resources like index action which gives a collection of objects where as show action needs an object to show. Hence member is used to get the action of a single object.
Here you can use
resources users do
resources member do
get :edit_profile
put :update_profile
end
end
You can also use
resources :users do
get :edit_profile, on: :member
put :update_profile, on: :member
end

How to delete / destroy user in rails app from database?

I recently watched the railscast episode #250 Authentication from Scratch (revised) and I have the signup / login / logout actions working. However I am working on creating an action to delete a user from the database, but I am currently experiencing some errors when I try to delete a user.
The users_controller.rb delete / destroy actions look like the following,
def delete
# the below line calls the destroy method / action
self.destroy
end
def destroy
session[:user_id] = nil
# #user = User.find(params[:id])
#user.destroy
# User.find(parmas[:id]).destroy
# the below line didn't delete the current user :(
# #user = User.destroy
redirect_to :controller=>'users', :action => 'new'
end
The error message I'm getting in the browser when I try to delete a user looks like the following.
The page that contains the delete link looks like the following, index.html.erb
<h1>Welcome
<% if current_user %>
<%= current_user.email %>
<% end %>
</h1>
<p>You have <%= current_user.credit %> credits.</p>
<!-- http://stackoverflow.com/questions/5607155/ -->
<%= link_to('Delete your account', :controller => 'users', :action => 'destroy') %>
routes.rb
Rails.application.routes.draw do
# the below generated route is not necessary
# get 'sessions/new'
# delete user route
#get 'delete' => 'users#delete'
# shortened routes, per railscast comment
get 'signup' => 'users#new'
get 'login' => 'sessions#new'
get 'logout' => 'sessions#destroy'
# get 'signup', to: 'users#new', :as 'signup'
# get 'login', to: 'sessions#new', :as 'login'
# get 'logout', to: 'sessions#destroy', :as 'logout'
resources :users
resources :sessions
root to: 'users#new'
# get 'users/new'
# the below line specifies JSON as the default API format
namespace :api, defaults: {format: 'json'} do
namespace :v1 do
resources :users
end
end
It stands to reason you're getting a NoMethodError, since you've never set the #user variable, that line is commented out:
def destroy
session[:user_id] = nil
# #user = User.find(params[:id]) <-- Commenting out this line was your problem
#user.destroy
Changing to
def destroy
session[:user_id] = nil
#user = User.find(params[:id])
#user.destroy
You should be good to go.
EDIT: one thing you'd probably want to do is change from using the old style of link_to, specifying the controller and action, and change to the new style, using route helpers. In this case, you'd use, i believe, link_to 'Delete your account', current_user, :method => :delete, but you can check by running rake routes, where it will list the helpers available based on your routes.rb file.
Well, I think you should make things a bit simpler and start from the dummiest thing, that works. First of all, if you use your controller as a resource, there would not be a delete action there, only destroy.
def destroy
User.find(params[:id]).destroy
session[:user_id] = nil
redirect_to new_user_path
end
P.S. once again, I assume that you have set resources :users in your routes.rb.
If you have a bunch of get|post|put|delete routes instead, just make sure you point the redirect correctly.

Ruby on Rails: Routing error

I am having trouble deleting and showing user records.
Here is my routes.rb
FinalApp::Application.routes.draw do
resources :users
devise_for :users, :controllers => { :registrations => 'admin' }
resources :projects
match "search" => "projects#search", :as => :search
root :to => 'projects#index'
end
Here is my admin controller:
class AdminController < ApplicationController
def index
#users = User.all
respond_to do |format|
format.html # index.html.erb
format.json { render :json => #users }
end
end
def create
#user = User.new(params[:user])
respond_to do |format|
if #user.save
format.html { redirect_to #user, notice: 'User was successfully created.' }
format.json { render json: #user, status: :created, location: #user }
else
format.html { render action: "new" }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
# GET /users/1
# GET /users/1.json
def show
#user = User.find(params[:id])
#user_user_id = params[:id]
respond_to do |format|
format.html # show.html.erb
format.json { render json: #user }
end
end
# GET /users/new
# GET /users/new.json
def new
#user = User.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #user }
end
end
# GET /users/1/edit
def edit
#user = User.find(params[:id])
end
# POST /users
# POST /users.json
# PUT /users/1
# PUT /users/1.json
def update
#user = User.find(params[:id])
respond_to do |format|
if #user.update_attributes(params[:user])
format.html { redirect_to #user, notice: 'User was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
# DELETE /users/1
# DELETE /users/1.json
def destroy
#user = User.find(params[:id])
#user.destroy
respond_to do |format|
format.html { redirect_to users_url }
format.json { head :no_content }
end
end
end
Here is my view:
<%= stylesheet_link_tag "admin" %>
<body>
<div id ="title1">Admin</div>
<div class ="menu"></div>
<div id ="section3">
<table id = "mytable">
<table border = "1">
<tr>
<th>Username </th>
<th>Email</th>
<th>First Name</th>
<th>Last Name</th>
<th>Admin?</th>
<th></th>
<th></th>
<th></th>
</tr>
<%= link_to "New User", admin_new_path %><br />
<% #users.each do |t| %>
<tr>
<td><%= t.username %></td>
<td><%= t.email %></td>
<td><%= t.firstname %></td>
<td><%= t.lastname %></td>
<td><%= t.admin %></td>
<td><%= link_to 'Show', t %></td>
<td> <%= button_to "Delete", t, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</table></br>
</body>
</html>
I can display the User database, but when I go to delete a record. I get this error No route matches [DELETE] "/users/11". I am new to rails so please remember this when trying to help. Thanks in advance.
Edit: here are my routes =>
admin_index GET /admin(.:format) admin#index
POST /admin(.:format) admin#create
new_admin GET /admin/new(.:format) admin#new
edit_admin GET /admin/:id/edit(.:format) admin#edit
admin GET /admin/:id(.:format) admin#show
PUT /admin/:id(.:format) admin#update
DELETE /admin/:id(.:format) admin#destroy
new_user_session GET /users/sign_in(.:format) devise/sessions#new
user_session POST /users/sign_in(.:format) devise/sessions#create
destroy_user_session DELETE /users/sign_out(.:format) devise/sessions#destroy
user_password POST /users/password(.:format) devise/passwords#create
new_user_password GET /users/password/new(.:format) devise/passwords#new
edit_user_password GET /users/password/edit(.:format) devise/passwords#edit
PUT /users/password(.:format) devise/passwords#update
cancel_user_registration GET /users/cancel(.:format) admin#cancel
user_registration POST /users(.:format) admin#create
new_user_registration GET /users/sign_up(.:format) admin#new
edit_user_registration GET /users/edit(.:format) admin#edit
PUT /users(.:format) admin#update
DELETE /users(.:format) admin#destroy
projects GET /projects(.:format) projects#index
POST /projects(.:format) projects#create
new_project GET /projects/new(.:format) projects#new
edit_project GET /projects/:id/edit(.:format) projects#edit
project GET /projects/:id(.:format) projects#show
PUT /projects/:id(.:format) projects#update
DELETE /projects/:id(.:format) projects#destroy
search /search(.:format) projects#search
root / projects#index
EDIT2: This is how my routes.rb file should have looked. Using rake routes I was able to change the paths to fix my problem.
FinalApp::Application.routes.draw do
# website home
root :to => 'projects#index'
# devise sessions (NB does not use admin/users controller)
devise_for :users, :controllers => { :registrations => 'users' }
# normal controllers
resources :users
resources :projects
# custom routes
match "search" => "projects#search", :as => :search
end
You should add resources :users to your routes.rb. In any case, you can always check rake routes in your console to see the available routes.
On a side note, the way you define you admin routes are not completely correct. Not everything is a get. For example, creating an admin would be a post. The easiest way is just to use something like resources :admins.
You have ended up with two routes leading to admin#destroy:
DELETE /users(.:format) admin#destroy
DELETE /admin/:id(.:format) admin#destroy
and yet you have no route which matches /users/xx, just a route which matches DELETE /users with an optional format bit. You have a route which matches /admin/11 so if you tried that it would work, however I would try to simplify things a bit.
Do you actually need to specify a controller on the devise resources? What exactly do you want to override there, as you have ended up with a load of routes (like cancel) which lead nowhere and some which clash...
Try a simpler routes definition (NB this requires renaming your AdminController UsersController instead, I would follow this convention as it will make your life easier, and match your other urls, so you end up with users/1 etc, not admin/1)
FinalApp::Application.routes.draw do
# website home
root :to => 'projects#index'
# devise sessions (NB does not use admin/users controller)
devise_for :users
# normal controllers
resources :users
resources :projects
# custom routes
match "search" => "projects#search", :as => :search
end
Then do rake routes to make sure you understand where the routes are pointing. You need a route which says (NB the :id bit):
DELETE /users/:id(.:format) users#destroy
or if you prefer an admin controller (and are willing to sort out the custom routes)
DELETE /admin/:id(.:format) admin#destroy
Perhaps before diving into this though you could read through the rails routing guide as it might clear a few things up for you:
http://guides.rubyonrails.org/routing.html
This appears to be a pretty standard use of Devise with your only notable difference being the name of your Controller. Therefore, the only thing you should need for devise routing is:
devise_for :users, :controllers => { :registrations => 'admin' }
Also, delete all of your "get 'admin/*'" entries. Not every HTTP method is a GET when you're working in a REST environment. Here is one article that discusses REST methods.

Rails Nested Singular Resource Routing

I have a simple User model with a singular nested Profile resource so in my routes.rb I have:
resources :users do
resource :profile, :only => [:edit, :update, :show]
end
This generates the expected routes:
edit_user_profile GET /users/:user_id/profile/edit(.:format) {:action=>"edit", :controller=>"profiles"}
user_profile GET /users/:user_id/profile(.:format) {:action=>"show", :controller=>"profiles"}
user_profile PUT /users/:user_id/profile(.:format) {:action=>"update", :controller=>"profiles"}
I've created a simple controller update method that updates the model and then redirects upon successful update:
def update
#profile = Profile.find_by_user_id(params[:user_id])
#user = User.find_by_id(params[:user_id])
respond_to do |format|
if #profile.update_attributes(params[:profile])
format.html { redirect_to( user_profile_path(#user, #profile), :notice => 'Profile was successfully updated.') }
else
# ...
end
end
end
The problem is that once the form is submitted, the form redirects to mydomain.com/users/4/profile.22 where 22 happens to be the id of the profile. Clearly this confuses the controllers since the routing interprets the '22' as the format.
My question is, how do I get this to redirect to mydomain.com/users/4/profile instead? I've tried the following variations on the redirect_to statement to no effect, they all result in the same incorrect url:
redirect_to( user_profile_path(#user), ... )
redirect_to( user_profile_path(#user, #profile), ... )
redirect_to([#user, #profile], ... )
redirect_to( #profile, ... )
What's more, using 'user_profile_path(#user)' elsewhere produces the correct url.
Any ideas? Oh, and I'm using Rails 3.0.0 and Ruby 1.9.2 if that helps.
After looking around, it appears that the form generating the update had an incorrect url. If anyone is seeing this issue, it's because I had my form set up as:
form_for [#user, #profile] do |f| ...
This caused the form action to have the incorrect url (of the offending form above). Instead, I used
form_for #profile, :url => user_profile_path(#user) do |f| ...
and everything seemed to work.
You should redirect to user_profile_path(#user) since as your routes says it is:
/users/:user_id/profile(.:format)
If you look at it closely, then you will see, that there is only :user_id parameter needed, thou it is only #user in a path.
/users/:user_id/profile/:id(.:format)
It would be correct if you had resource*s* :profiles in your routes.rb, then as well you could use your path as in your example.
user_profile_path(#user) should be correct. You're sure that one is returning mydomain.com/users/4/profile.22?

Resources