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