Is this a valid devise route? - ruby-on-rails

Hey guys is this a valid route to declare in the config/routes file? I want to a user to directed to a certain registration controller based on a condition but it doesn't seem to generate the route (when I do a rake routes command)
if Rails.application.config_for(:app)['app_for'] == 'vodacom'
devise_for :users, controllers: { registrations: "vodacom/users/registrations"}
else
devise_for :users, controllers: { registrations: "users/registrations"}
end

No, routes are generated on app load, so whatever the initial value is what is going to be the route created. So only one of these two routes will work.
You can check in the controller, and if your condition is true, redirect them to the other controller. But just create both without the conditional and do the conditional in the controller and redirect.

Related

add your own custom route to devise

i've seen a bunch of posts on how to rename already-declared routes in devise. I want to expand devise to have my own route check for and idle session. I am implementing a simple js check every 1 minute that I want to hit 'check_active' in the devise sessions controller. I tried this but no luck:
devise_scope :sessions do
get 'check_active'
end
Is there way to expand devise with a custom route (not rename an already-existing one) ?
UPDATE - almost there, i did this
# already had this in routes
devise_for :users, :controllers =>
{ registrations: 'registrations',
confirmations: 'confirmations',
sessions: 'sessions',
passwords: 'passwords',
omniauth_callbacks: "omniauth_callbacks"}
# added this
devise_scope :sessions do
get '/check_active' => 'sessions#check_active'
end
I have a js firing, i have it get '/check_active' as rake routes shows this:
check_active GET /check_active(.:format)
But when it fires, the controller 404s with
AbstractController::ActionNotFound (Could not find devise mapping for path "/check_active".
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]
):
If you are overwriting Devise's default controllers, it is not any different from any other controller to add your own route.
After you create your devise controllers to overwrite, do the following:
Under sessions_controller declare a method
# app/controllers/devise/sessions_controller.rb
def check_active
# do what you want to do
end
And in your router:
# config/routes.rb
devise_scope :sessions do
get 'check_active', to: "devise/sessions#check_active"
end
I was trying the same thing and realized that the scope should be for user and not sessions, also ensure that it has to be singular.
devise_scope :user do
get '/check_active' => 'sessions#check_active'
end
Edit: Adding link to help docs for better understanding

Devise generated mailer URLs with devise_for in Rails scopes

I'm building a Rails application with a Javascript framework, so Rails is serving the backend API.
For now, the app is simply implementing all the devise views and actions.
In order to do so, the Rails app accepts only JSON calls to its /api/ URLs, and requires that Devise is working with JSON calls only, so that I defined them like the following:
Rails.application.routes.draw do
scope :api, module: :api, constraints: { format: 'json' } do
devise_for :users, controllers: {
confirmations: 'devise/confirmations',
registrations: 'devise/registrations',
sessions: 'sessions'
}
resources :users
end
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
root to: 'home#index'
get '*path', to: 'home#index'
end
To explain what is going on here:
First part is defining the API URLs including the devise ones and defines the API resources (for now only :users)
Then it defines the root route
Finally forwards any calls to the Javascript router (allowing to manage page reload or external links like the email links).
All is working fine with this, excepted the account confirmation email link.
The confirmation email sent has a link including /api/ (http://localhost:3001/api/users/confirmation?confirmation_token=XLDVqqMZwXg6dszyV_nc) while it should be without (Expected URL: http://localhost:3001/users/confirmation?confirmation_token=XLDVqqMZwXg6dszyV_nc).
How can I make devise sending the confirmation email (and all the other emails) without the /api/ part?
Update
Looking deeper the devise source code I found that the confirmation mailer view template is using the confirmation_url Rails named route, which is correct.
In my case, I need ALL the devise routes to be limited to the /api/ route, and to the JSON format, excepted few routes to be 2 times defined: a first time out of the /api/ scope in HTML format (which will be forwarded to my JavaScript app), and a second route within the /api/ scope which will be called by the JavaScript app.
Example: Expected account creation confirmation execution stack
Rails receives the request to /users/confirmation?confirmation_token=XLDVqqMZwXg6dszyV_nc
Rails forward the request to the Javascript router
Javascript framework loads the corresponding page
Javascript page loads a service which will call the /api/users/confirmation?confirmation_token=XLDVqqMZwXg6dszyV_nc Devise route to confirm the account
You should be able to simply add the two additional routes after the initial API routes. Like this:
Rails.application.routes.draw do
scope :api, module: :api, constraints: { format: 'json' } do
devise_for :users, controllers: {
confirmations: 'devise/confirmations',
registrations: 'devise/registrations',
sessions: 'sessions'
}
resources :users
end
devise_for :users, controllers: {
confirmations: 'devise/confirmations',
registrations: 'devise/registrations'
}
root to: 'home#index'
get '*path', to: 'home#index'
end
It is hard to say for sure without also seeing the front end code, but it is fine to have both routes.
There are two ways you can solve your problem.
Make the links in the emails be of json format (have '.json' at the end)
or
Allow actions for links from emails to be available through html (without format: 'json' constraint).
This example shows how to do it for email confirmation action.
scope :api, module: :api, constraints: { format: 'json' } do
# skip routes generation for `confirmations` controller
devise_for :users, skip: [:confirmations]
# add allowed `confirmations` actions manually (all except for `show`)
as :user do
get 'confirmation/new', to: 'devise/confirmations#new', as: :new_user_confirmation
post 'confirmation', to: 'devise/confirmations#create'
end
end
# add `confirmations#show` action outside of `/api` scope to be available from email link by `html`
as :user do
get 'confirmation', to: 'devise/confirmations#show', as: :user_confirmation
end
If you don't want to use Devise's HTML views and actions, you can customize Devise controllers or write your own. This example shows how to customize Devise confirmations controller:
# app/controllers/confirmations_controller.rb
class ConfirmationsController < Devise::ConfirmationsController
def show
# do whatever you want
end
end
# config/routes.rb
scope :api, module: :api, constraints: { format: 'json' } do
# tell Devise to use your custom confirmations controller
devise_for :users, controllers: {confirmations: "confirmations"}
end
Updated
Also, if you want your email links to have nothing to do with Devise API, you can customize the Devise mailer views to change the email texts and put there the links you need.
The rails generate devise:views command will generate standard Devise views including mailer templates that you can customize.

How to configure routes for different user models using devise?

I have two different user groups, User and Flyer.
I have generated views and controllers for both the models using,
rails g devise:controllers users/flyers
and for views:
rails g devise:views users/flyers
This is my routes.rb:
Rails.application.routes.draw do
devise_for :flyers
devise_for :admins
resources :currencies
resources :broadcasts
devise_for :users, controllers: {
sessions: 'users/sessions',
registrations: 'flyers/registrations'
}
devise_for :flyers, controllers: {
sessions: 'flyers/sessions',
}
end
But I am getting error for devise for flyers controllers route:
Invalid route name, already in use: 'new_flyer_session' You may have defined two routes with the same name using the `:as` option, or you may be overriding a route already defined by a resource with the same naming. For the latter, you can restrict the routes created with `resources` as explained here: http://guides.rubyonrails.org/routing.html#restricting-the-routes-created
How can I have different routes?
Thanks
Remove devise_for :flyers from top

Customize part of devise custom routes, basically I don't know Rails routing =(

I feel like my brain left the building when I was learning Rails routing... I can't figure this out.
So I have customized some devise controller, and therefore I have updated the route file like so:
devise_for :users, controllers: {
registrations: "users/registrations",
sessions: "users/sessions",
passwords: "users/passwords"
}
That works GREAT. It gives me paths like this:
new_user_registration GET /users/sign_up(.:format) users/registrations#new
The challenge now is I want to run an A/B test using Google Analytics where I need 2 more pages for the sign up.
So in my controller this is how I would modify:
class Users::RegistrationsController < Devise::RegistrationsController
def new
end
# ADD BELOW
def new_control
end
def new_test
end
end
But I can't figure out how to modify my routing so that I have these 2 new routes in additional to the old new_user_registration_path (note the named path helper for these new ones don't matter so much to me because I never actually use it)
GET /users/sign_up/control(.:format) users/registrations#new_control
GET /users/sign_up/test(.:format) users/registrations#new_test
Note that I want to keep all the other lovely routes the devise_for code has created, e.g., the create and edit actions
You can access specify the route normally as you would do in a rails app. Only thing you need to do is wrap the route inside a device_scope. This also shows up as warning when you try to access the route without adding the device_scope.
So in your case routes should be like:
devise_scope :user do
get 'users/sign_up/control' => 'users/registrations#new_control'
get 'users/sign_up/test' => 'users/registrations#new_test'
end

Namespacing all controllers for devise

I am using Devise with multiple models (three to be exact) and each role has some different interactions. For example, after the user model signs up I override a devise method to redirect them to a specific welcome path, where with the employer model I take them to a credit card form, etc.
As a result, I need to namespace everything. Namespacing the views and controllers are not tough, however, I was wondering if there is a way to namespace the controllers without having to specify EVERY devise controller.
For example, is there a way to basically do this:
devise_for :employers, :controller => "employers"
Instead of having to do this:
devise_for :employers, :controllers => {
:registrations => "employers/registrations",
:sessions => "employers/sessions",
:confirmations => "employers/confirmations",
:passwords => "employers/passwords",
:unlocks => "employers/unlocks",
:mailer => "employers/mailer"
}
Might seem trivial but when you have three models to maintain it could get a bit much.
Take a look at the following answer from Devise within namespace. Simply namespacing in the routes.rb will not produce the desired results. You'll have to generate controllers for each action you want. For sessions for example, You will have to create a new controller called Sessions in the controller Employer namespace:
bundle exec rails g controller employer/sessions
then subclass the new session controller from devise session controller to bring in all the Devise methods required to properly handle sessions:
class Employer::SessionsController < Devise::SessionsController
end
and change your 'devise_for :employers, :controller => "employers"' line in config/routes.rb to the following:
devise_for :employers, :controllers => { :sessions => "employer/sessions" }
Finally, as an optional step, you can generate views to app/views/employer/sessions directory. You can do this my setting "config.scoped_views = true" inside config/initializers/devise.rb and running the following to generate views scoped to employers:
rails generate devise:views users
This should generate templates at app/views/employer/sessions/new. Otherwise, the new session controller will just use the default view templates.
Hope this helps!
Will it work by just saying: devise_for :employers, :path => "employers" ?

Resources