Devise hide the user id from the url - ruby-on-rails

When editing a user in devise the edit_user_registration_path route is:
edit_user_registration GET /users/edit(.:format) devise/registrations#edit
I would like to have a route to edit a user's profile without disclosing the user_id in the url however my route is:
edit_profile GET /profiles/:id/edit(.:format) profiles#edit
How can I create a similar route and hide the user_id from the url?
EDIT
Ok, I worked this one out... partially using:
http://guides.rubyonrails.org/routing.html#singular-resources
I have created a singular resource in my routes.rb file
resource :profile
This now allows me to view the current user's profile with /profile and edit the current user's profile with /profile/edit
However when I edit the current user's profile and click update I am redirected to /profile.1? /profile.2 /profile.3 and so on all display the current user's profile.
Where does the profile.X come from and how do I simply redirect back to /profile after I update?
My update action is simply:
def update
#profile.region = set_region(params[:postal_code], params[:country])
#profile.assign_attributes(profile_params)
#profile.save
#profile.user.update_attributes (user_params)
respond_with(#profile)
end

Your question is
Where does the profile.X come from and how do I simply redirect back
to /profile after I update?
Run the following command
$ rake routes | grep profile
profile POST /profile(.:format) profiles#create
new_profile GET /profile/new(.:format) profiles#new
edit_profile GET /profile/edit(.:format) profiles#edit
GET /profile(.:format) profiles#show
PATCH /profile(.:format) profiles#update
PUT /profile(.:format) profiles#update
DELETE /profile(.:format) profiles#destroy
As you can see profile_path receives no parameter. A parameter passed to profile_path will be interpreted as format. You can try the following in Rails console
> app.profile_path
=> "/profile"
> app.profile_path(1)
=> "/profile.1"
> app.profile_path("json")
=> "/profile.json"

Related

Unable to route to a method in my controller

I’m using Rails 4.2.5. I’m trying to set up my controller so that when a logged in user visits /users/edit, they see my form where they can edit some of their profiles. So in config/routes.rb I have
resources :users
…
get "users/edit" => "users#edit"
then in “app/controllers/users_controller.rb” I have
def edit
#user = User.find(session["user_id"])
render 'edit'
end
but when I visit “http://localhost:3000/users/edit” in a browser, I get the error
The action 'show' could not be found for UsersController
It is true I have no “show” method in my controller, but that is not where I want the user to go. I want them going to the edit method.
You are trying to go to the show action with this link:
http://localhost:3000/users/edit
You have this route for the show action:
GET /users/:id(.:format) users#show
(:id) is (edit)
Because you have defined first RESTful route:
resources :users
Which includes all routes listed below:
users_path GET /users(.:format) users#index
POST /users(.:format) users#create
new_user_path GET /users/new(.:format) users#new
edit_user_path GET /users/:id/edit(.:format) users#edit
user_path GET /users/:id(.:format) users#show
PATCH /users/:id(.:format) users#update
PUT /users/:id(.:format) users#update
DELETE /users/:id(.:format) users#destroy
and then
get "users/edit" => "users#edit"
Rails always finds first match. In this case show action of RESTFul routes will be applied:
GET /users/:id(.:format) users#show
and the other route will be ignored.
Solution: Change the order of the routes. That way edit route will be applied first.
The problem is that you're mixing a resource route with your own edit method, and "Rails routes are matched in the order they are specified" so it's matching the resources show route users/:id and stopping there.
You need to move your edit route above the resource.
Alternatively, read the linked guide and see if you can add edit as a collection route to the resource, and except the resources edit method. You may also need to except the show method, but it's worth having a play and seeing what you come up with. Routing is an important aspect and worth time to understand.
remove get "users/edit" => "users#edit" from your routes, change to resources :users, only: [:edit] (or more if actions you need them), remove the render 'edit' from your controller (default action).
Visit http://localhost:3000/users/1/edit to see the edit page for user_id 1 (there can't be an edit page for all users, you have to specify the id)

Rails application route cannot access from Grape API

I'm requesting for any user from a different rails application. I'm using grape gem. The below code is the requested user's information sending controller action.
but unfortunately it is showing error:
NoMethodError (undefined method `profile_url' for #<Grape::Endpoint:0xdadef8c>):
What is the problem? My rake routes showing the url does exists.
module V1
class User < Grape::API
version 'v1', using: :path
format :json
prefix :api
resource :user do
desc "find any user"
params do
requires :email, type: String
requires :password, type: String
end
get :create do
user = User.find_by_email(params[:email])
if user.present?
if user.valid_password?(params[:password])
{user: user, profile_url: profile_url(user.profile)}
else
{:notice => "Invalid password for email: #{params[:email]}"}
end
else
{:notice => "No user found with email: #{params[:email]}"}
end
end
end
end
end
rake routes | grep profile:
profiles GET /profiles(.:format) profiles#index
POST /profiles(.:format) profiles#create
new_profile GET /profiles/new(.:format) profiles#new
edit_profile GET /profiles/:id/edit(.:format) profiles#edit
profile GET /profiles/:id(.:format) profiles#show
PATCH /profiles/:id(.:format) profiles#update
PUT /profiles/:id(.:format) profiles#update
DELETE /profiles/:id(.:format) profiles#destroy
Make sure you mounted the resource properly.
You may need something like this:
mount API::v1::User
See more about mounting here
Also, take a look at this post. Might be helpful to see how you can mount your resource while using Grape gem.
You can do it like this:
Rails.application.routes.url_helpers.profile_url(user.profile)

Why does my controller keep routing my link_to toward "show" action? Rails 4

So I am pretty stumped. I am new to Ruby on Rails (I am using Rails 4) and I have been trying to figure out for the last two days why my link_to tag keeps routing my login action to show instead. I removed the show action from my controller and even deleted show.html.erb and yet Rails remains persistent in trying to route it to a show action that no longer exists.
I removed all my redirect_to functions, and the link_to I create takes me to the correct page localhost:8000/users/login but now displays the error Unknown Action: The action 'show' could not be found for UsersController.
I have read up other SO questions that were similar, and some suggest that it may be an issue with jquery_ujs, which I removed from my file to see if it was the problem, but I still ended up with the same result.
The files in my views directory are as follows:
views
users
new.html.erb
login.html.erb
Here's what my code looks like:
The link_to in users/new (new.html.erb)
<li><%= link_to "Login", users_login_path %></li>
routes.rb
resources :users
root 'users#new'
get 'users/create'
get 'users/login'
users_controller.rb
class UsersController < ApplicationController
def new
end
def create
#user = User.create(:username => params[:username], :password => params[:password])
#user.save
#users = User.all
end
def login
#message = "Success"
end
end #end class
login.html.erb (Just testing an output here to see if it ever gets to this page)
<h3><%= #message %></h3>
Output of rake routes command
Prefix Verb URI Pattern Controller#Action
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
root GET / users#new
users_create GET /users/create(.:format) users#create
users_login GET /users/login(.:format) users#login
I figured out what the problem was:
I needed to remove resources :users from the routes.rb file.
Everything is working as expected now. After doing a little bit of research it seems that the problem with having resources :users in there is that when browsers try to access the page they try to perform a command by using an HTTP method, which is either GET, POST, PUT, DELETE, or PATCH.
When the page looks for an incoming command which in this case was GET /users/login, it tries to map it to a controller action. If the first matching route is resources :users, it will send it to the show action.
It seems that this is due to the default CRUD system Rails uses where each HTTP method represents a CRUD action (correct me if I am wrong):
GET is show
POST is create
DELETE is destroy
PATCH is update
I got most of this research from Rails Routing from the Outside In, Section 2.1.

Link helper VS typing URL

Something weird is happening and I don't know why.
When I use the helper <%= link_to "New game", new_game_path %>, my new game form does not submit.
But when I acesses the view typing the URL localhost:3000/games/new form works just well
Any idea how to solve that?
Thanks,
Here my rake routes
Prefix Verb URI Pattern Controller#Action
root GET / games#index
user_sessions GET /user_sessions(.:format) user_sessions#index
POST /user_sessions(.:format) user_sessions#create
new_user_session GET /user_sessions/new(.:format) user_sessions#new
edit_user_session GET /user_sessions/:id/edit(.:format) user_sessions#edit
user_session GET /user_sessions/:id(.:format) user_sessions#show
PATCH /user_sessions/:id(.:format) user_sessions#update
PUT /user_sessions/:id(.:format) user_sessions#update
DELETE /user_sessions/:id(.:format) user_sessions#destroy
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
delete_progress_progresses POST /progresses/delete_progress(.:format) progresses#delete_progress
progresses POST /progresses(.:format) progresses#create
search GET /search(.:format) games#search
game_levels GET /games/:game_id/levels(.:format) levels#index
POST /games/:game_id/levels(.:format) levels#create
new_game_level GET /games/:game_id/levels/new(.:format) levels#new
edit_game_level GET /games/:game_id/levels/:id/edit(.:format) levels#edit
game_level GET /games/:game_id/levels/:id(.:format) levels#show
PATCH /games/:game_id/levels/:id(.:format) levels#update
PUT /games/:game_id/levels/:id(.:format) levels#update
DELETE /games/:game_id/levels/:id(.:format) levels#destroy
insert_levels_game POST /games/:id/insert_levels(.:format) games#insert_levels
games GET /games(.:format) games#index
POST /games(.:format) games#create
new_game GET /games/new(.:format) games#new
edit_game GET /games/:id/edit(.:format) games#edit
game GET /games/:id(.:format) games#show
PATCH /games/:id(.:format) games#update
PUT /games/:id(.:format) games#update
DELETE /games/:id(.:format) games#destroy
login GET /login(.:format) user_sessions#new
logout POST /logout(.:format) user_sessions#destroy
My route file
Rails.application.routes.draw do
root :to => 'games#index'
resources :user_sessions
resources :users
resources :progresses, :only => :create do
collection do
post 'delete_progress'
end
end
get 'search' => 'games#search'
resources :games do
resources :levels
member do
post 'insert_levels'
end
end
get 'login' => 'user_sessions#new', :as => :login
post 'logout' => 'user_sessions#destroy', :as => :logout
end
Sure, you can use string as relative URL. This will never crash since rails will not try to resolve your routes building it. My guess is, that you might have a typo of some sort.
There is no reason why this wouldn't work. I have searched your git app for "new_game_path" but could not find a single example where you use this code.
I have only found < a href="/games/new">New game</a> in your layout.
Replace it with <%= link_to 'New Game', new_game_path %> this works in your app. I have just tested it.
If you intend to use internationalization at some point, you should avoid standard HTML links. They will not keep your locale persistent.
form
You mention that your "form does not submit"
This is not a problem with your link_to - it's an issue with your form; they are two different issues:
--
link_to
link_to takes you to a new page. It's a helper method to help create the equivalent of Your text
This means that if you're sending requests to your new action, it should not matter how the users get there - only how the action is rendered.
The typical case for a form is as follows:
#app/views/games/new.html.erb
<%= form_for #game do |f| %>
<%= f.text_field :attribute %>
<%= f.submit "test" %>
<% end %>
#app/controllers/games_controller.rb
Class GamesController < ApplicationController
def new
#game = Game.new
end
end
--
Fix
When you mention your new game form does not submit, that's an issue with your form itself. This could be due to a number of reasons, but typically with the way in which you're rendering the form
To fix this, you'll need to detail how you're rendering your form & how you'd like it to submit
Update
Having read your updated comments, if the form works when you send the requests to the "naked" url, the issue may not be with the form itself.
As a rule of thumb, you'll always want to use the Rails helpers when defining links etc. In your application layout, I found that you posted "pure" HTML to create a link. This is bad because if the Rails syntax changes, or your routes change, your application won't update correctly.

Rails undefined method `user_index_path`

I'm new to Ruby and Rails and working my way through the Rails Tutorial. Early on, I realized that I accidentally created my model as Users rather than User, so I've been going with that ever since.
It hasn't been an issue until I tried to implement the sign up page, and now whether going to pages or running the test visit signup_path for the sign up page, I keep getting the following error:
undefined method `users_index_path' for #<#<Class:0x007f9e3e1d91b8>:0x007f9e3e1d1ff8>
I can't figure out what's going wrong here. When I run rake routes I get the following:
~/Coding/rails_projects/sample_app (sign-up*) ☔ rake routes
Prefix Verb URI Pattern Controller#Action
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
root GET / static_pages#home
help GET /help(.:format) static_pages#help
about GET /about(.:format) static_pages#about
contact GET /contact(.:format) static_pages#contact
signup GET /signup(.:format) users#new
From that output, it looks to me like there should be a method users_index_path.
If it helps, my Users controller is the following:
class UsersController < ApplicationController
def new
#user = Users.new
end
def show
#user = Users.find(params[:id])
end
end
Using Rails 4.0.5.
Output from a page giving me the error:
Please keep in mind users_index_path is being called by Rails and not by me.
with
users GET /users(.:format) users#index
POST /users(.:format) users#create
you'll have a users_path method that will generate the /users path. That path will lead to either the index action (with a GET request) or the create action (with a POST request).
Under the hood, form_for #user will call the users_path method and set things up to fire a POST on submit (when #user is a new record). The URL helper method is calculated dynamically from the class name. This is ok if you're using Rails' defaults, but if you've defined custom routes you'll need to specify the URL explicitly.
With this out of the way, let's look at your problem.
A model with a plural name, e.g. class Users, will confuse rails.
When you pass #user to form_for, Rails will look at the class name, notice that it's a plural word, and try its best to deal with the ambiguity.
Normally it would be user_path for singular routes (show, update, delete) and users_path for the plural ones (index, create). Here, however, users_path must be used for the singular routes, and Rails will fallback to use users_index_path for index and create.
This would be all right.... but you have defined the routes using the default statement, probably with something like
resources :users
Which is correct, but not compatible with your model name.
Either rename your routes (bad) or rename your model (good).

Resources