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?
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.
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.
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.
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.
When you use
#The code in question
module Api
module V1
class UserController < ApplicationController
end
end
end
ApplicationController
definition 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 :)
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With