Mike GehardMike Gehard
Devise 1.1.3 gotcha...
edit Posted by Mike Gehard on Friday November 05, 2010 at 04:23PM

In the continued saga that is the Rails 2.3.10 to Rails 3.0.1 upgrade, I found this little nugget today...you want to add a custom action to a controller that inherits from a Devise controller. Here are the steps that you need to follow:

1) Create a custom controller that overrides some out of the box Devise actions as well as adds a new method.

class RegistrationsController < Devise::RegistrationsController
  def update
     # do something different here
  end

  def deactivate_owner
    # deactivate code here
  end
end

2) You have to tell Devise to use the new controller in routes.rb as well as add the new route to the new action.

devise_for :owners, :controllers => { :registrations => "registrations" } do
  post "deactivate_owner", :to => "registrations#deactivate_owner", :as => "deactivate_owner_registration"
end

When we initially implemented this, our route definition looked like this:

post "deactivate_owner", :to => "registrations#deactivate_owner", :as => "deactivate_owner_registration"
devise_for :owners, :controllers => { :registrations => "registrations" }

When it was implemented this way, we kept getting a AbstractController::ActionNotFound exception. Once we passed the block to devise_for seen in #2, everything worked fine.

Comments

  1. José Valim José Valim on November 07, 2010 at 02:36PM

    Exactly! In Devise 1.0.x we used the URL to try to guess which scope was being accessed.

    In Devise 1.1 use the constraints API in the router to tell which scope is being accessed. So you can either define your route inside devise_for or use "devise_scope" or "as" method.

    This gives more flexibility to allow you to access whatever URL you want through Devise. :)

    In Devise master we also improved the error message when AbstractController::ActionNotFound is raised, so people have a better idea of what happened.

  2. Mike Gehard Mike Gehard on November 07, 2010 at 03:00PM

    Thanks for the note Jose and thanks for making Devise great! I'm really enjoying using it, especially the new version for Rails3.

  3. John Bruce John Bruce on November 09, 2010 at 12:13PM

    This was an absolute life saver, thank you for this post! I'm performing this exact customization now and couldn't figure out the abstract controller error.

  4. Bharat Ruparel Bharat Ruparel on December 01, 2010 at 02:57PM

    Hello Mike, I am trying to follow your advise for my customization work and not having much luck with it. So instead of RegistrationsController, I call my controller UsersController as shown below:

    class UsersController < Devise::RegistrationsController skip_before_filter :require_no_authentication <-- I override this

    def index # shows a list of users end

    def new
       @user = User.new
        @user.build_profile  <-- for has one profile relationship
    end
    
     def change_status
        # marks a user as active or inactive
     end
     ...
    

    end

    To account for this and following your advise here, I have the following entries in the routes.rb file:

    FileManager::Application::routes.draw do

    devise_for :users, :controllers => {:registrations => "users"} do
       get "index", :to => "users#index", :as => "index"
    end
    
    resources :users <- if I don't do this I get the following error
    # no route matches /users
    

    end

    If you can provide some further guidance, I will appreciate it. Thanks.

    Bharat

  5. Mike Gehard Mike Gehard on December 02, 2010 at 05:59AM

    Bharat,

    I am confused about what further guidance you need. Is there a specific problem you are having or error you are seeing?

    Mike

  6. Bharat Bharat on December 02, 2010 at 01:22PM

    Hello Mike, Thanks for your response and willingness to help out. I found a nice reference which is more inline with what I was trying to do and things are working now. Here is the reference:

    https://github.com/fortuity/rails3-mongoid-devise

    I will be posting my application on the github guite soon so that everyone can benefit from it. Currently, it uses authlogic which I am replacing with Devise and CanCan. Here is the URL:

    http://github.com/bruparel/file_manager3

    Regards, Bharat

  7. Steve Steve on December 05, 2010 at 12:46AM

    Dang I wish I had seen this blog post before I dug into the Devise source code to figure out why it kept throwing UnknownAction exceptions.

    One thing to note is that if you want to add a route that might interfere with the other Devise routes (ie, users#show at "users/:id"), you need to define them after the call to devise_for):

    devise_for :users, :controllers => {:registrations => "users"}
    devise_scope :user do
      get "users/:id", :to => "users#show", :as => "user"
    end
    
  8. Law Law on December 10, 2010 at 10:56AM

    Yes! It works. I'm starting to think Devise needs a serious round of documentation. Who's on that? if no one, i volunteer. I just have to learn the hell out of it first. I'm still not convinced that it's so much better than Authlogic. But then Authlogic has no documentation either.