# Roda Controller Adds controller functionality to Roda ## Configuration Configure your Roda application to use this plugin: ```ruby plugin :controller ``` You can already register your controllers: ```ruby plugin :controller, controllers: { users: UsersController } # Infer controller key to 'users' plugin :controller, controllers: [UsersController] # Infer controller key to 'users_handler' plugin :controller, controllers: [UsersHandler] ``` ```ruby You may also register controllers later, inside your application class declaration: ```ruby register_controller UsersController register_controller MoviesController # Passing a list of controllers register_controller [UsersController, MoviesController] # Explicitly declaring the controller key register_controller :users, UsersHandler register_controller :movies, MoviesHandler ``` ## Usage ### Controller Naming The controller class is not required to follow any naming convention, specially if you specify explicitly the controller key when registered. However if it ends with `Controller` this will be stripped from the controller key if it is inferred. I.E. `UsersController => 'users'` and `UsersHandler => 'users_handler'` ### Controller Definition You just need to implement the methods with the action names you are going to use: ```ruby class UsersController def index "User Index" end def show(user_id) "User Show ##{user_id}" end end ``` ### Dispatching to controllers Call `#dispatch` whenever you want to receive the result of the controller action, this is a textbook RESTful routing definition: ```ruby r.on("users") do r.is do r.get do dispatch('users#index') end r.post do dispatch('users#create', args: r.params) end end r.on(:id) do |user_id| r.is do r.get do dispatch('users#show', args: user_id) end r.patch do # requires all_verbs plugin to be loaded dispatch('users#update', args: [user_id, r.params]) end r.delete do # requires all_verbs plugin to be loaded dispatch('users#destroy', args: user_id) end end end end ``` ### Receiving dispatched responses You may expose the controller responses using the `@responds_with` variable: ```ruby # users_controller.rb class UsersController def show(user_id) user = user: User.find(user_id) @responds_with = { user: user, best_movie: Movie.best_for(user) } end end # app.rb r.get do dispatch('users#show', args: user_id) # Do stuff with @user and @best_movie, or access @responds_with directly # if the instance variable cannot be overwritten end ``` ### Rendering Views If you are using the render plugin you can use the `#controller` method instead of `#dispatch`. It receives the same parameters but will call the `#view` method with the following convention: ```ruby controller('users#show', args: user_id) # will call view('users/show') ``` ### Initializing Controllers You may specify parameters for controller initialization, to provide context to your actions without polluting the method arguments: ```ruby # users_controller.rb class UsersController attr_reader :request, :response def initialize(request, response) @request = request @response = response end # be able to access the request and response inside actions # app.rb ## inside routes dispatch('users#update', args: [user_id, r.params], inject: [request, response]) ## registering controller register_controller(:users, -> { |req, res| UsersController.new(req, res) } ``` ### Advanced Configuration You can setup default arguments for the `#dispatch` and `#controller` methods: ```ruby # Will always initialize controllers with request and response args plugin :controller, inject: ->{ [request, response] } ``` ### DRYing up By following conventions you may dry everything up. This: - Creates a `RodaController` class to be inherited on your controllers - Exposes request and response variables inside actions - Adds helper methods to your actions - Automatically loads all controllers inside `controllers` folder ```ruby # roda_controller.rb class RodaController attr_reader :request, :response # Access request and response methods def initialize(request, response) @request = request @response = response end # Enables respond_with exposed_variable: local_variable def respond_with(opts) @responds_with ||= {} @responds_with.merge!(opts) end # Get list of all controllers def self.descendants ObjectSpace.each_object(Class).select { |klass| klass < self } end end # app.rb ## configuring the plugin plugin :controller, inject: ->{ [request, response] } ## automatically registering all controllers inside controllers folder Dir["controllers/*.rb"].each { |file| require_relative file } RodaController.descendants.each do |controller| controller_key = Roda::RodaPlugins::Controller.underscore(controller.name) controller_proc = -> (req, res) { controller.new(req, res) } register_controller(controller_key, controller_proc) end ``` ## Contributing Bug reports and pull requests are welcome on GitHub at https://github.com/badosu/roda-controller ## License The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).