This app is being built on Devise 3.0 and Rails 4.1
I have a User object with two subclasses (Lender and Business) through STI. After a Business registers and confirms their email address, they are redirected to a form to fill out more information about themselves (This data is stored in a new object called SuppForm).
A business object has_one supp_form. I'm getting an error when the business confirms their email and is redirected to the form.
The error
ActionController::RoutingError (uninitialized constant SuppFormsController)
routes.rb (I used [ ] for business routes because I don't want them overlapping with the routes used in other places of the application)
# User type routes, needed to define specific sign out route to allow get request, not delete request
devise_for :users, skip: :registrations do get '/users/sign_out' => 'devise/sessions#destroy' end
devise_for :lenders, skip: :sessions, :controllers => {:registrations => "lenders/registrations"}
devise_for :businesses, skip: :sessions, :controllers => {:registrations => "businesses/registrations"}
resources :businesses, :only => [] do
resource :supp_form
end
business.rb
class Business < User
has_one :supp_form
accepts_nested_attributes_for :supp_form
end
supp_form.rb
class SuppForm < ActiveRecord::Base
belongs_to :business
end
supp_form_controller.rb
class SuppFormController < ApplicationController
before_filter :authenticate_user!
def new
#suppform = SuppForm.new
end
private
def supp_form_params
params.require(:supp_form).permit(:first_name, :last_name, :work_phone_number, :business_address, :business_postal_code)
end
end
application_controller.rb
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
def account_url
return new_user_session_url unless user_signed_in?
case current_user.class.name
when "Business"
business_root_path
when "Lender"
lender_root_path
else
root_path
end if user_signed_in?
end
def after_sign_in_path_for(resource)
if resource.sign_in_count == 1 && resource.type == "Business"
new_business_supp_form_path(resource.id)
else
stored_location_for(resource) || account_url
end
end
You can see in application_controller.rb I redirect the business to the supp_form based on the number of times they've logged in. I also try and pass through the business's ID by calling resource.id and passing that through the request. The URL when I get the error is: http://xxxxxxxxxx/businesses/14/supp_form/new
Looks like a pluralization problem. Change the controller to a plural name.
class SuppFormsController < ApplicationController
before_filter :authenticate_user!
# etc
end
Does sound weird though since there really is only a single supp_form generated from the controller. You could also try to setup inflections to prevent rails from attempting to pluralize the word supp_form in config/initializers/inflections.rb
ActiveSupport::Inflector.inflections do |inflect|
inflect.uncountable %w( supp_form )
end
Related
If a user is logged in with Devise, I'd like to redirect them to their Posts index.
/username/posts
According to the Devise docs
I can use an authenticated block.
authenticated :user do
....
end
But I need the user's username to redirect there. Something like this.
authenticated :user do |user|
get '/', to: user_posts(user)
end
But this is not supported.
How to redirect with the current user to an authenticated root?
Edit:
NOT trying to do a after sign in Devise path. Trying to achieve a permanent root for logged in users and one for logged out users.
Try that:
class ApplicationController < ActionController::Base
def after_sign_in_path_for(user)
user_posts_url(user)
end
end
So you can do something like this
in your routes:
#config/routes.rb
Rails.application.routes.draw do
devise_for :users, :controllers => {
...
}
authenticate :user do
namespace :users do
...
root :to => 'posts#index' # /users/posts # this will only be accessible to login users
end
end
root :to => 'pages#index' #/pages this is accessible to all people
end
you will need:
#app/controllers/user_controller.rb
class UserController < ApplicationController
before_action :authenticate_user!
end
and
#app/controllers/users/posts_controller.rb
class Users::PostsController < UserController
def index
#posts = current_user.posts
end
...
end
I hope that this helps
I have a user model with an admin submodel.
class Admin < User
end
I have devise set up and a 'type' column in the user model. The routes look like this:
devise_for :users, :controllers => { :sessions => 'sessions' }, :skip => :registrations
devise_for :admins, :skip => :sessions
I am unclear on how to override devise so I can access an admin using the current_user helper.
Right now name is undefined from <%= current_user.name %>
Is an admin not also a user? I'm not sure why current_user is nil.
In my sessions_controller I have:
class SessionsController < Devise::SessionsController
def create
rtn = super
sign_in(resource.type.underscore, resource.type.constantize.send(:find, resource.id)) unless resource.type.nil?
rtn
end
end
Have a nested resource as such
class Dealer < ActiveRecord::Base
has_many :vehicles
end
and
class Vehicle < ActiveRecord::Base
belongs_to :dealer
end
below are my routes.
resources :dealers do
resources :vehicles, :except => [:index]
end
resources :vehicles, :only => [:index]
looking at the wiki at the github page for cancan I did the following:
class VehiclesController < ApplicationController
load_and_authorize_resource :dealer
load_and_authorize_resource :vehicle, :through => :dealer
def index
#vehicles = Vehicle.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: #vehicles }
end
end
end
but now when the admin tries to go to the index page with the abilities:
def initialize(user)
user ||= User.new # guest user (not logged in)
if user.has_role? :admin
can :manage, :all
end
end
I get
Couldn't find Dealer with id=
what do i need to change for admin to still be able to do all the actions and yet have others be checked before they can do any action.
The problem is not that he is not authorized to this action. The problem is that CanCan tries to fetch an instance of dealer to load all its vehicles and you have not provided a :dealer_id within params[:dealer_id]. Cancan assumes you would be loading only dealer's vehicles in this controller because you used an load_and_authorieze :through. This authorization should be used within Dealers::VehiclesController.
As long as you only loading vehicles just use load_and_authorize_resource :vehicle. And because load_and_authorize will set #vehicles for you within the before filter there is also no need to load the vehicles explicitly with Vehicle.all.
load_and_authorize is just a convenient method and it assumes some defaults. Once you will come to a point where you have some more complex use case. It will be time to throw away this method and just use CanCan's authorize!, can? and a properly configured Vehicle .accessible_by (for listing) methods.
When using load_and_authorize_resource :vehicle, through: :dealer it expects to receive a dealer_id in the request in order to authorize the dealer.
Since you use except: :index in your routes dealer_id will not be automatically included in the request.
If you don't want to authorize the dealer in the index action you can do something like this (taken from Can Can wiki)
class CommentsController < ApplicationController
load_and_authorize_resource :post
load_and_authorize_resource :through => :post
skip_authorize_resource :only => :show
skip_authorize_resource :post, :only => :show
end
I have two devise models, Individual and Group. I'm trying to share similar behavior for Registrations/Confirmations (send users to a page that informs them that an email has been sent, or send them to the edit page after confirmation, etc.)
My issue is that this works for Individuals, only. It has yet to work for Groups.
config/outes.rb:
devise_for :individuals, :controllers => {:confirmations => "Confirmation", :registrations => "Registrations"}
devise_for :groups, :controllers => {:confirmations => "Confirmation", :registrations => "Registrations"}
app/controllers/registrations_controller.rb:
class RegistrationsController < Devise::RegistrationsController
def after_inactive_sign_up_path_for(item)
"/post_sign_up?email=#{item.email}"
end
end
app/controllers/confirmation_controller.rb:
class ConfirmationController < Devise::ConfirmationsController
def after_confirmation_path_for(name, resource)
case resource.class
when Individual then edit_individual_path resource
when Group then edit_group_path resource
else super name, resource
end
end
end
The above code works for individuals, only. Can't figure out why though.
I was focused so heavily on the provided lines in routes.rb, I failed to notice another "devise_for :groups" at the top of the file. Apparently devise will override previous values in this case. Stupid mistake.
for scale & no errors - better to devide.
admin_registration_controller.rb:
class AdminRegistrationsController < Devise::RegistrationsController
end
user_registration_controller.rb:
class UserRegistrationsController < Devise::RegistrationsController
end
routes:
devise_for :admins, controllers: { registrations: 'admin_registrations' }
devise_for :users, controllers: { registrations: 'user_registrations' }
I am currently using Cancan and my users basically have different 'roles'.
I only want people to be able to register 'consumer' user accounts and for business accounts admins will be doing that.
So now, I have this in my ability.rb
def initialize(user)
user ||= User.new
...
# You can only create accounts that are consumers
can :create, User do |user|
user.role? :consumer
end
and in my controller/users/registrations_controller.rb
class Users::RegistrationsController < Devise::RegistrationsController
load_and_authorize_resource
end
and config/routes.rb:
devise_for :users, :controllers => {
:registrations => "users/registrations"
}
Now when I visit the registration page, I am seeing "uninitialized constant Registration" with NO stack trace whatsoever. Any ideas?
My code example
class ApplicationController < ActionController::Base
authorize_resource
check_authorization
end
class Users::SessionsController < Devise::SessionsController
skip_authorize_resource
skip_authorization_check
end
For load_and_authorize_resource you will need skip_load_and_authorize_resource. And all this code is applicable for custom devise's controller. Just create one.
The issue is with the routes, please follow the following steps
1. $ rake routes, you will see the list of routes
2. In your config/routes.rb write the route you need, In my case the route to create a new user was,
devise_for :users, :controllers => { :new_user_registration => "users/registrations#new" }
3. restart rails server