Weijian Ma
Weijian Ma

Reputation: 21

Controllers inside Rails engines (gems)

I'm learning how to build a Rails gem (engine, to be more specific). I first read some existing open source code like Devise, but I can't understand the controllers inside it. In app/controllers there is _devise_controller.rb_ with module hierarchy

 class DeviseController < Devise.parent_controller.constantize

but in lib/devise/controllers/ there are also many controllers with module hierarchy

module Devise 
  module Controllers

what's the difference between these controllers (like which is called when I get "users/sign_up")? Can someone who has more experience using Devise explain?

Upvotes: 2

Views: 237

Answers (2)

Richard Peck
Richard Peck

Reputation: 76784

I've included controllers in a gem I wrote some time back.

One of the main reasons for using the namespace is because your entire gem should be under the duress of a single module:

#lib/exception_handler.rb
module ExceptionHandler

    #Exception Handler
    class Exceptions < Rails::Engine

This means that if you're calling a controller from within the gem (which is meant to be self-contained), you'll generally have to invoke it inside the module:

ExceptionHandler::ExceptionController.action(:show).call(env) }

--

In the sense of Devise, it makes sense for them to include their controllers in a namespace for two reasons:

  • It permits them to call their controllers from within their module
  • They are able to include the controllers without the need of external dependencies

which is called when I get "users/sign_up"

The devise controllers can be broken down by the routes Devise sets:

 new_user_session     GET       /users/sign_in       {controller:"devise/sessions", action:"new"}
 user_session         POST      /users/sign_in       {controller:"devise/sessions", action:"create"}
 destroy_user_session DELETE   /users/sign_out       {controller:"devise/sessions", action:"destroy"}

These are just routes for the sessions controller (which handles login etc).

There are other routes including registrations etc.

The key here is to understand that Devise has to work "out of the box" -- otherwise most people wouldn't use it. It achieves this by self-containing its controllers, ensuring that, as sanfor recommended, they are not conflicted.

If you have more specific requests, I'll gladly answer them for you.

Upvotes: 1

Roope Hakulinen
Roope Hakulinen

Reputation: 7405

I assume that the Devise controllers are inside their own module to not pollute the global namespace. Check for example the case in this answer where the new class is based on Devise's RegistrationController

class RegistrationsController < Devise::RegistrationsController

if it weren't inside the Devise the name RegistrationsController would already be taken.

The controllers under app/controllers/devise are the actual controllers that the router redirects requests to. The ones under lib/devise/controllers are helpers for the controllers and thus are in module Devise::Controllers for convenience.

When users/sign_up is called, it is routed to _registrations_controller.rb:6_. This isn't done the normal way via routes.rb probably because Devise needs to adjust the URLs per application since you don't always use users as the path. Instead is done by devise/rails/routes.rb which is where the line

mount_devise_token_auth_for 'User', at: 'auth'

from actual applications routes.rb takes to.

Upvotes: 1

Related Questions