To limit devise auto generated routes, I have this in my route file...
## config/routes.rb
# Restrict auto generated devise routes
devise_scope :user do
resource :users,
only: [:new, :create, :edit, :update],
controller: 'users/registrations',
path_names: { new: 'sign_up' },
as: :user_registration
end
Controller:
## app/controllers/users/registrations_controller
module Users
# Copied by `devise` generator so we could override things.
class RegistrationsController < Devise::RegistrationsController
def new
# some logic
end
def create
# some logic
end
# # Overriding and call to `super` for these two method removes unused routes warning, I don't want this
# # rubocop:disable Lint/UselessMethodDefinition
# def edit
# super
# end
# def update
# super
# end
# # rubocop:enable Lint/UselessMethodDefinition
rails_best_practices linter is giving warning restrict auto-generated routes users (only: [:new, :create]) if I don't override the edit & update methods in RegistrationsController.
Is there a way to disable RestrictAutoGeneratedRoutesCheck for those routes?
Or what would be the most feasible way to resolve this warning? Thank you.
What about a custom rails_best_practices.yml with a tweaked RestrictAutoGeneratedRoutesCheck entry? See: https://github.com/flyerhzm/rails_best_practices
Go to rails_best_practices.yml and you can apply the ignored_files option on any rule by giving a regexp or array of regexp describing the path of the files you don't want to be:
In your case RestrictAutoGeneratedRoutesCheck{ignored_files: 'routes.rb'}.
Related
I have the following code
application.rb
config.autoload_paths += %W(#{config.root}/config/routes)
routes.rb
Rails.application.routes.draw do
root to: 'summary#index'
extend General
end
/config/routes/general.rb
module General
def self.extended(router)
router.instance_exec do
# devise routes
devise_for :users, controllers: { sessions: 'users/sessions' }
end
end
end
I get uninitialized constant General when loading the app.
I''m using Ruby 2.2.6 and Rails 5.0.2
in rails 6, you can use draw(:general), which will look for route definition in config/routes/general.rb
You can emulate this with an initializer:
module RoutesSubfolder
# Extension to Rails routes mapper to provide the ability to draw routes
# present in a subfolder
#
# Another solution would be to add the files to `config.paths['config/routes']`
# but this solution guarantees the routes order
#
# Example: <config/routes.rb>
#
# Rails.application.routes.draw do
# # this will eval the file config/routes/api.rb
# draw :api
#
# Example:
# draw :'api/whatever' # loads config/routes/api/whatever.rb
#
def draw(name)
path = Rails.root.join('config', 'routes', "#{name}.rb")
unless File.exist?(path)
raise StandardError, "Unable to draw routes from non-existing file #{path}"
end
instance_eval(File.read(path), path.to_s, 1)
end
end
ActionDispatch::Routing::Mapper.prepend(RoutesSubfolder)
The only difference with what you proposed is that:
you don't need to change the autoload_path
in general.rb, you directly declare your routes the same way you'd do in config/routes.rb inside the Rails.application.routes.draw do block
I have a problem with the devise gem, I have this controller.
class AdminController < ApplicationController
before_action :authenticate_user!
def index
end
def per
end
def po
end
end
When redirect to sign_in form , shows nothing
sign_in form
These are my routes:
match 'po' => 'admin#po', :via => :get
match 'per' => 'admin#per', :via => :get
match 'admin' => 'admin#index', :via => :get
match 'admin/index' => 'admin#index', :via => :get
match 'admin/per' => 'admin#per', :via => :get
match 'admin/po' => 'admin#po', :via => :get
devise_for :users, :controllers => { :omniauth_callbacks => "callbacks" }
root 'home#index'
I have three templates: application, admin and home
I overwrite the default route after log in
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
#before_action :authenticate_user!
def after_sign_in_path_for(resource)
#request.env['omniauth.origin'] || stored_location_for(resource) || admin_path
admin_path
end
end
My last gem installed:
gem 'bootstrap-sass'
You need to run the generator for Devise views which will copy the necessary files in your views folder:
Run:
rails g devise:views
There is more information on configuring the Devise views here
Your problem probably isn't with Devise, it looks systemic to me.
#config/routes.rb
namespace :admin do
root "application#index" #->
resources :model_controller, path: "", only: :index do #-> url.com/admin/...
collection do
get :po #-> you shouldn't really have this
get :per #-> you shouldn't really have this
end
end
end
devise_for :users, :controllers => { :omniauth_callbacks => "callbacks" }
This will give you the following:
#app/controllers/admin/application_controller.rb
class Admin::ApplicationController < ApplicationController
before_action :authenticate_user!
def index
# do something here
end
end
This gives you the ability to create a custom "dashboard" type page for your admin area, from which you'll be able to use controllers bound to models.
Your po and per actions really shouldn't be there - they are not part of the CRUD system
In regards to your Devise views, the other answers are correct in that you would be best to generate the Devise views in your app:
rails generate devise:views
This won't solve your problem (hence why I downvoted the other answers). It will simply put the views in your app. It will do nothing apart from put code in a different place.
You will need to debug the issue:
Check the action you're seeing at /users/sign_in
Check the code in the <body> tags (which you haven't shown)
If the HTML is there, there will be some other issue preventing it from loading
If there is no HTML, it will likely mean a problem with the core of Devise
What I would recommend you do is the following:
Generate your views
From your screenshot, show us the contents of the <body> tag
Screenshot your console log (this will show any errors)
Update your question with the above
This will give you a much clearer perspective on what the potential issue will be, and allow other community members to better define the solution.
Hi I'm getting this error
Circular dependency detected while autoloading constant
Subdomain::Settings::ThemesController
in my Rails 4.0 app whenever I try to access the stated controller. In fact I get similar errors for any of the other controllers name-spaced with the themes controller.
I have the following controllers name-spaced under Settings which itself is name-spaced under Subdomain.
Are these controllers defined correctly? Can anyone spot why this circular dependency error is cropping up?
# app/controllers/subdomain/settings/security_controller.rb
module Subdomain
class Settings::SecurityController < BaseController
def edit
...
end
end
end
# app/controllers/subdomain/settings/themes_controller.rb
module Subdomain
class Settings::ThemesController < BaseController
def edit
...
end
end
end
# app/controllers/subdomain/settings/profiles_controller.rb
module Subdomain
class Settings::ProfilesController < BaseController
def edit
...
end
end
end
# app/controllers/subdomain/base_controller.rb
class Subdomain::BaseController < ApplicationController
...
end
And the following routes configuration
MyApp::Application.routes.draw do
constraints(Constraints::SubdomainRequired) do
scope :module => :subdomain do
namespace 'settings' do
root to: 'security#edit'
resource :theme, only: [:create, :edit, :update], :controller => 'themes'
resource :profile, only: [:edit, :update], :controller => 'profiles'
resource :security, only: [:edit, :update], :controller => 'security'
end
end
end
end
The solution was I needed to rewrite each controller like so
module Subdomain
module Settings
class ProfileController
...
instead of
module Subdomain
class Settings::ProfileController
I have a resource, say Product, which can be accessed by two different user classes: say Customer and Admin. There is no inheritance between these two.
I am using Devise for authentication:
# config/routes.rb
devises_for :customers
deviser_for :admins
I have these two controllers:
# app/controllers/customers/products_controller.rb
class Customers::ProductsController < ApplicationController
and
# app/controllers/admins/products_controller.rb
class Admins::ProductsController < ApplicationController
Now depending on who logs in (Customer or Admin), I want products_path to point to the corresponding controller. And I want to avoid having customers_products_path and admins_products_path, that's messy.
So I have setup my routes as such
# config/routes.rb
devise_scope :admin do
resources :products, module: 'admins'
end
devise_scope :customer do
resources :products, module: 'customers'
end
This doesn't work. When I login as a Customer, products_path still points to Admins::ProductsController#index as it is the first defined.
Any clue? What I want to do might simply be impossible without hacking.
UPDATE
According to the code, it is not doable.
It turns out the best way to achieve that is to use routing constraints as such:
# config/routes.rb
resources :products, module: 'customers', constraints: CustomersConstraint.new
resources :products, module: 'admins', constraints: AdminsConstraint.new
# app/helpers/customers_constraint.rb
class CustomersConstraint
def matches? request
!!request.env["warden"].user(:customer)
end
end
# app/helpers/admins_constraint.rb
class AdminsConstraint
def matches? request
!!request.env["warden"].user(:admin)
end
end
I stored the constraint objects in the helper folder because I don't really know the best place to put them.
Thanks to #crackofdusk for the tip.
For this you will need to override the existing after_sign_in_path_for method of devise. Put this in your app/controllers/application_controller.rb
def after_sign_in_path_for(resource)
if resource.class == Admin
'/your/path/for/admins'
elsif resource.class == Customer
'/your/path/for/customers'
end
end
Note: If you want to implement previous_url that was requested by user then you can use it like this:
session[:previous_url] || 'your/path/for/admins'
I am trying to create a custom controller in the admin section of Spree and reuse the devise authentication mechanism. How do I go about doing this. I have simply tried to do the following:
module Spree
module Admin
class WorkflowController < Spree::Admin::BaseController
end
end
end
And I created a route like this:
namespace :admin do
resources :workflow, :only => [:index, :show]
end
I am getting the following error:
ActionController::RoutingError (uninitialized constant Admin):
So, any thoughts on how to best create a custom controller or am I just doing something wrong with this?
This is happening because your controller is nested inside the Spree namespace, but your routes are not. If you want to extend Spree's routes, then do this:
Spree::Core::Engine.routes.draw do
namespace :admin do
resources :workflow, :only => [:index, :show]
end
end