Why doesn't the Devise registrations edit action need params? - ruby-on-rails

I am learning a Rails course, and I have this in my routes
devise_for :users,
path: '',
path_names: { sign_up: 'register', sign_in: 'login', edit: 'profile', sign_out: 'logout' },
controllers: { omniauth_callbacks: 'omniauth_callbacks', registrations: 'registrations' }
This will generates routes like
edit_user_registration GET /profile(.:format) registrations#edit
In my view I just need to use edit_user_registration_path while normally it should be sth like user_path(:id). If I write edit_user_registration_path(1) it will redirect to .../profile.1
As I know normal Rails edit route should have params[:id]. Why in this case it doesn't need and how edit_user_registration_path(1) generates .../profile.1?

The routes don't need and don't take an ID parameter since they act on the current user which is stored in the session and not passed through the parameters.
Similarly if you wanted to create a controller that deals with items belonging to the current user you could do:
scope :user do
resources :items, controller: :user_items
end
class UserItemsController
before_action :authenticate_user
# GET /user/items
def index
#items = current_user.items
end
end
If you instead where building something like an admin interface where you can edit other users on the system an id param would be necessary.

Related

Custom Routing in Rails 5

I'm having some issues with custom routing. What I'm looking to do is remove the model from the route and dynamically use the record name.
so instead of:
site.com/events/my-event
I would like it to be:
site.com/my-event
I hacked this to work with the below code, only issue is I can't access my admin namespace as it's being treated as an event record (and any other route):
get('/:id', to: redirect do |params, request|
id = request.path.gsub("/", "")
"/events/#{id}"
end)
I know this redirect is not right, I'm just not well versed in routing options. How should this be done properly?
routes.rb
Rails.application.routes.draw do
resources :events, param: :id, path: "" do
get 'login', to: 'sessions#new', as: :login
get 'logout', to: 'sessions#destroy', as: :logout
post 'sessions', to: 'sessions#create', as: :session_create
end
namespace 'admin' do
root "events#index"
resources :sessions, only: [:create]
get 'login', to: 'sessions#new', as: :login
get 'logout', to: 'sessions#destroy', as: :logout
resources :events
end
end
Rails lets you specify what a routing URL should look like:
https://guides.rubyonrails.org/routing.html#translated-paths
You don't need redirect.
You need to match all requests to one controller/action.
get '/(*all)', to: 'home#app'
Inside this action check what is coming in params and render appropriate view.
PS: it will capture all requests, even for not found images, js, etc.
(1) To fix /admin to go to the right path, move the namespace line above the events resources so that it is matched first:
Rails routes are matched in the order they are specified 2.2 CRUD, Verbs, and Actions
# routes.rb
namespace :admin do
root "events#index"
#...
resources :events
end
resources :events, param: :name, path: ""
Use :param and :path to match for site.com/myevent instead of site.com/events/:id
Your events controller:
# events_controller.rb
class EventsController < ApplicationController
# ...
private
def set_event
#event = Event.find_by(name: params[:name])
end
end
Your admin events controller:
# admin/events_controller.rb
class Admin::EventsController < ApplicationController
# ...
private
def set_event
#event = Event.find params[:id]
end
end
TIP: To get a complete list of the available routes use rails routes in your terminal 5.1 Listing Existing Routes

Ruby on Rails - User Devise Routing

I'm having issues with routing with Devise and my Users model. I was trying to get sign_out to work and found an answer that suggested this.
// routes.rb
devise_for :users do
get '/users/sign_out' => 'devise/sessions#destroy'
get '/users/sign_in' => 'devise/sessions#create'
end
And while this works for signing out, if I use just that I cannot view a User.
No route matches [GET] "/users/1"
However, if I add back resources :users, I run into the first issue where sign_out or sign_in try to view a User.
Couldn't find User with 'id'=sign_out
How do I add /users/index to the devise_for loop?
Thanks for your help.
Try adding resources :users after your devise_for block.
You can also use the following:
devise_for :users, path: '', path_names: { sign_in: 'login', sign_out: 'logout'}

Resetting user password when devise_for routes are in scope

In my application all routes are scoped to a locale, that user has selected like this:
scope ":locale", locale: /#{SpreeI18n::Config.supported_locales.join('|')}/ do
devise_for :users, skip: :omniauth_callbacks
get '/', to: 'homepage#index', :as => :homepage
end
When I want to send reset password instructions like User.find(1).send_reset_password_instructions, there is a problem:
Devise::Mailer#reset_password_instructions: processed outbound mail in 4249.9ms
ActionView::Template::Error: No route matches {:action=>"edit", :controller=>"devise/passwords", :reset_password_token=>"-zyuNkscVkwFn2awdm27"} missing required keys: [:locale]
How can I pass locale so that I can send the reset token?
Let's create a custom controller for password:
Customize routes.rb
scope ":locale", locale: /#{SpreeI18n::Config.supported_locales.join('|')}/ do
devise_for :users, skip: :omniauth_callbacks, controllers: { passwords: 'my_passwords' }
get '/', to: 'homepage#index', :as => :homepage
end
my_passwords_controller.rb
class MyPasswordsController < Devise::PasswordsController
def create
resource_params.merge!(locale: 'en') # use 'en' for eg
super
end
end
Then send_reset_password_instructions function will take your customized resource_params when sending the email.
Please refer to devise sourcecode to understand what devise does in detail!

Abstracting rails route

I want to replace the normal /users/:id route that is created by the resources command, with a more abstract /profile route. It won't be possible to view other users profiles in my app, and therefor the current route is unnecessary specific.
I have tried to overwrite the route created by 'resources :users' with:
get '/profile', to: 'users#show'
and other variances and combinations, but can't seem to get it right. Either the controller can't find the user because of a missing id or it simply can't find the route.
Thanks for the help!
You can use this code in routes.rb file:
resources :users, :except => :show
collection do
get 'profile', :action => 'show'
end
end
It will generate url "/users/profile".
But, if u want to use only '/profile', then don't create route as collection inside users resources block.
resources :users, :except => :show
get 'profile' => "users#show", :as => :user_profile
It will redirect '/profile' to show action in users controller.
I suggest simply adding a users/me route pointing to the show action of your UsersController like so:
resources :users, only: [] do
collection do
get 'me', action: :show
end
end
You can also use the match keyword in routes.rb file.
match 'users/:id' => 'users#show', as: :user_profile, via: :get

Rails Devise user controller in subfolder

I am using omniauth and found devise using a subfolder for this(in official example) controllers/users/omniauth_callbacks_controller.rb. I need to create a User show page as well as other actions for User so I decide to create a new UsersController inside a controllers/users folder. Now it looks like
class Users::UsersController < ApplicationController
def show
#user = User.find(params[:id])
end
end
routes.rb
My::Application.routes.draw do
devise_for :users, :controllers => { :omniauth_callbacks => "users/omniauth_callbacks" }
match 'users/:id' => 'users/users#show'
root :to => 'home#index'
end
it works but the route created is unnamed
rake routes gives
/users/:id(.:format) users/users#show
without GET and route_name
so I'm unable to use it for example after login redirect. Is there a better way to realize the subfolder routes structure and is it good idea to group controllers like this?
You just need name your route in your route.rb
match 'users/:id' => 'users/users#show', :as => 'user'
After that you can call this route by user_url(user.id)
See example on guides : http://guides.rubyonrails.org/routing.html#naming-routes

Resources