Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ruby namespacing

I'm pretty new to ruby, coming from a php background, but something is not clicking with me.

So, let's say I have a Ruby on Rails application and I am versioning my API like so:

app
|_controllers
  |_api
  | |_v1
  | | |_application_controller.rb
  | | |_user_controller.rb
  | |_application_controller.rb
  |_application_controller.rb

With the class structure with

# Versioned API V1 app controller
module Api
  module V1
    class ApplicationController
    end
  end
end

# Versioned API app controller
module Api
  class ApplicationController
  end
end

# Root app controller
class ApplicationController
end

#The code in question
module Api
  module V1
    class UserController < ApplicationController
    end
  end
end

So the question is, does ruby look for Api::V1::ApplicationController, Api::ApplicationController, or ApllicationController for extending?

Does the < ApplicationController look for it's own namespace unless I specify Api::ApplicationController? If so, how do I specify the root one?

like image 397
GingerTech Avatar asked Apr 28 '15 12:04

GingerTech


People also ask

What is Namespacing in Ruby?

A namespace is a container for multiple items which includes classes, constants, other modules, and more. It is ensured in a namespace that all the objects have unique names for easy identification. Generally, they are structured in a hierarchical format so, that names can be reused.

What is Namespacing in rails?

Namespacing allows us to nest a controller inside of another directory within our controllers directory. It also changes the route that a user would visit along with the rails path helper prefix.

What is a Ruby mixin?

Mixins in Ruby allows modules to access instance methods of another one using include method. Mixins provides a controlled way of adding functionality to classes. The code in the mixin starts to interact with code in the class. In Ruby, a code wrapped up in a module is called mixins that a class can include or extend.

What does double colon mean in Ruby?

The :: is a unary operator that allows: constants, instance methods and class methods defined within a class or module, to be accessed from anywhere outside the class or module.


2 Answers

When you use

#The code in question
module Api
  module V1
    class UserController < ApplicationController
    end
  end
end

ApplicationControllerdefinition will be searched in Api::V1 then if not found in Api then if not found in the root namespace.

I agree it could be confusing, that's why I tend to use absolute paths like so: ::ApplicationController

If ever I'd need Api::ApplicationController, I'd write ::Api::ApplicationController

Basically the :: tells ruby to start from the root namespace and not from where the code lives.


Sidenote

Be aware that there are vicious cases in Rails development mode. In order to gain speed, the strict minimum is loaded. Then Rails looks for classes definitions when needed.

But this sometimes fails big time example, when you have say ::User already loaded, and then look for ::Admin::User. Rails would not look for it, it will think ::User does the trick.

This can be solved using require_dependency statements in your code. Speed has a cost :)

like image 159
apneadiving Avatar answered Nov 16 '22 02:11

apneadiving


I would rather suggest don't write ApplicationController in namespace, I would suggest to follow following

Note: If you are building professional api's it always good to have Api::V1::BaseController inheriting from ActionController::Base, though I am giving solution to your specific case

Ref this post: Implementing Rails APIs like a professional

1) Define application controller in usual way in app/controllers/application_controller.rb as

class ApplicationController < ActionController::Base
end 

2) Define base api controller namely Api::V1::BaseController in app/controllers/api/v1/base_controller.rb which will inherit from ApplicationController (your case) like

class Api::V1::BaseController < ApplicationController
end 

3) Define your api controllers like Api::V1::UsersController in app/controllers/api/v1/users_controller.rb which will inherit from Api::V1::BaseController

class Api::V1::UsersController < Api::V1::BaseController
end 

4) Add all subsequent controllers like Api::V1::UsersController (step 3)

Then routing will contain namespaces routing in config/routes.rb

namespace :api do
  namespace :v1 do
    resources :users do 
      #user routes goes here 
    end
    # any new resource routing goes here 
    # resources :new_resource do 
    # end
  end
end
like image 29
Pramod Shinde Avatar answered Nov 16 '22 02:11

Pramod Shinde