Monday, March 6, 2017

create a wrapper controller for all calls to web services in rails

Leave a Comment

I am working to creating a wrapper for my existing application controllers.

For example, i have two controllers accepting similar set of parameters and similar methods.

Code is as below

class EmployeeController < ApplicationController    def list   end  end   class DepartmentController < ApplicationController    def list   end  end 

end point would be http://localhost:3000/employee/list & http://localhost:3000/department/list

What is the best way to create wrapper controller and invoke either of the controllers action.

is this way correct, where we check certain parameters and create objects accordingly or are there better ways to do it

class WrapperController < ApplicationController     def list     if params["which"].eql?("employee")       data = EmployeeController.new(params).create     else       data = DepartmentController.new(params).label     end    end end 

end point would be http://localhost:3000/wrapper/list

Any help would be appreciated. Thanks in advance.

4 Answers

Answers 1

This WrapperController sounds like a really bad idea. Especially instantiating another controller and calling a method on it. I don't recall seeing such pattern anywhere. Rails does a lot of magic around request/response cycle, so calling another controller will most likely break something later on. I am just guessing that cookies may not work, or rendering can be broken etc.

Anyway, what you probably want is better organise your business logic inside Rails application. As a starting point I strongly recommend reading this article. Based on limited information from your question it is hard to give a good answer for your particular case.

For example, you can implement a query object:

class EmployeesQuery   def initialize(params)     # initialize some internal variables   end    def list     # write code for fetching employees based on passed params   end end  class DepartmentsQuery   def initialize(params)     # initialize some internal variables   end    def list     # write code for fetching employees based on passed params   end end  class QueryFactory   QUERIES = {     "employee" => EmployeeQuery,     "department" => DepartmentQuery   }    get self.get_query(resource)     QUERIES[resource] || raise("Some exception")   end end 

Now you can create a ListsController:

class ListsController < ApplicationController   def index     data = QueryFactory.get_query(params[:which]).list     # render specific view based on requested resource     # and rescue possible exception from get_query method   end end 

And in config/routes.rb:

get "/:which/list" => "lists#index" 

This can be later extended with more resources and having separate query objects for each will make it more maintainable. The only problematic thing is how to render generated results, but you can use similar pattern for selecting correct template to render.

If you want to have similar pattern for creating objects, you should look at service object pattern. It is described in linked article.

Also you can kind solve your problem with much simpler way, just by changing config/routes.rb a little bit.

get "/:controller/list", to: :list 

It will route /employee/list to EmployeeController and /department/list to DepartmentController. And basically it will route to any valid controller, so maybe you want to tweak it a little bit and add some restrictions.

Hope that helps. Cheers.

Answers 2

Why shouldn't we just forward it with same request

class WrapperController < ApplicationController     def list     if params["which"].eql?("employee")       controller = EmployeeController.new     else       controller = DepartmentController.new     end     controller.request = request     controller.response = response     controller.list    end end 

Answers 3

You already have this with Application Controller, that's why its the parent controller. The standard way would be to add a before_action in ApplicationController that performs the check and then redirects to the proper controller.

class ApplicationController      before_action :check_emp_or_dept      def check_emp_or_dept         if employee_params.fetch("which", "").eql?("employee")             @employee = Employee.find employee_params['id']              redirect_to @employee         else             @department = Department.find department_params['id']             redirect_to @department         end     end    protected     # handle strong params according to what your model requires     def department_params       params.require(:department).permit(:param1, :param2)     end      # handle strong params according to what your model requires     def employee_params         params.require(:department).permit(:param1, :param2)     end  end 

Note this code above will need to be reworked to your specific setup for strong params. I would argue that it's not a good idea to create Employees/Departments blindly based on the passed params, although you can easily change the find methods above to "find_or_create_by" methods if you so choose.

Answers 4

You can do this easily in routing (i.e. routes.rb file) using constraints:

get '/wrapper/list', to: 'employee#list',    constraints: lambda { |request|      request.query_parameters["which"] == "employee"   } get '/wrapper/list', to: 'department#list',    constraints: lambda { |request|     request.query_parameters["which"] != "employee"   } 
If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment