Having a controller action call an action in a different controller

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

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.

I very much recommend you don't do this. The common databasey stuff
should be in models, you can share presentation stuff via helpers and
shared partials.

Fred

If you want to consolidate the retrieval of data that's necessary for the widgets to be displayed, it sounds like you want to abstract that into a module that you can include into your controller. From there, as Fred suggests, use partials and helpers to do the rendering.

Here is a concrete example of how to create a class to help you render the same HTML content in different views, althought it doesn't access the database.

  #101 Refactoring Out Helper Object - RailsCasts

Another thing that helps display *related* models in a different view is the plugin called attribute_fu.

  http://jamesgolick.com/tags/attribute_fu

I guess the million dollar question is:

  How do you access a totally different unrelated model/data/ controller in a totally different view?

For that, I think you would probably create something like the first example, but put it in the /lib directory and have it access the model of interest. Does anybody have a good concrete example of this online?

Hope this helps.

David :slight_smile: