Does anyone know how to go about having a controller action call an action in a completely different controller?
The reason for wanting to do this is that my Rails app has several actions that are common across all pages (these actions are part of the page layout, and these pages are produced by several different controllers). These actions modify the database. The app uses Ajax heavily to update the current page rather than performing a complete page refresh. The logic to update the current page is specific to the controller that originated the page. My rjs templates for the common actions currently have lots of conditional logic in them (for handling all the different pages that a common action can be called from), so I'm trying to find a better way of doing this (the current approach is not object oriented and is getting difficult to maintain).
So, the pattern I would like to use is to have the common actions handled by a controller that knows how to update the database (but is view agnostic), and then delegating the rendering responsibilities (i.e. generate JavaScript via RJS for updating the current page) to the controller that originated the page. This is where the idea of having one controller call another controller comes into play.
Here is a contrived example that demonstrates what I'm trying to accomplish:
# Controller that allows a user to view and interact with widgets class WidgetViewController < ApplicationController def all_widgets # action that returns a list of all widgets # logic to set up the all_widgets rjs for displaying list of widgets
# save off the controller and action which produced this view session[:current_controller] = "WidgetViewController" session[:current_action] = "all_widgets" end
def refresh_all_widgets # logic to set up the refresh_all_widgets rjs for refreshing the current page end
def recent_widgets # action that returns a list of widgets recently created # logic to set up the recent_widgets rjs for displaying list of recently created widgets
# save off the controller and action which produced this view session[:current_controller] = "WidgetViewController" session[:current_action] = "recent_widgets" end
def refresh_recent_widgets # logic to set up the refresh_recent_widgets rjs for refreshing the current page end end
# Controller that handles common actions related to creating, editing and deleting widget models class WidgetController < ApplicationController def create # creates a widget in the database widget = Widget.new(params[:widget]) if ( widget.save() ) # delegate rendering responsibility to controller that originated the current page controller_class = eval(session[:current_controller]) controller = controller_class.new controller_refresh_action = "refresh_#{session[:current_action]}" controller.send(controller_refresh_action) # call the "refresh" action to delegate rendering responsibilities else # appropriate error handling end end end
The code above does end up calling the appropriate "refresh" action in the WidgetViewController, however it crashes down inside of Rails when trying to render that action. After digging into how Rails spins up a controller to service a request, I can see why this isn't working - after instantiating a controller, Rails performs set up on the controller, and then passes it request and response objects.
Thanks in advance, Denis