views:

754

answers:

4

I'm pretty new to Rails and have an issue which I can't quite get my head around as to the architecturally 'correct' way of doing it.

Problem relates to what I kinda call sub-controllers. The scenario is this:

I have a series of pages, on which is a panel of some form containing some information (think the user panel on gitHub top right).

So, in my app, I have controllers that generate the data for the pages and render out the responses which is fine, but when it comes to this panel, it seems to me that you would want some sort of controller action dedicated to generating this panel and it's view.

Question is, how do you go about doing this? How do I render a 'sub controller' from within a view?

+1  A: 
Maximiliano Guzman
+2  A: 

I would put the logic in a helper or a module. (http://api.rubyonrails.org/classes/ActionController/Helpers/ClassMethods.html)

Then render partials where you want these things displayed. (http://api.rubyonrails.org/classes/ActionView/Partials.html)

DanSingerman
+2  A: 

Like Herman said, if it's logic that you need generated after the controller hands off to the view (ie, the Pages controller generates a page view, but you want a customized panel) then put it in a helper. Or, call a separate method in your Pages controller before handing off to the view. Or, if it's a lot of logic, create a Module and stick it in your /lib folder. So you could have a whole Panel module with methods that generate different parts of your Panel and which are called by your controller. But if you want to call these methods from within the view, then you should use a helper instead.

insane.dreamer
+2  A: 

I dont think a module is what is required here, modules are required for shared behaviour across a small subset of your classes.

What I think is required here is the understanding of the inheritance of ApplicationController and also layouts

so, for example, my layout might look like:

<html>
<head><title>Foo</title></head>
<body>
  <%= render :partial => (current_user ? "/shared/user_widget_bar" : "/shared/login_bar") %>
  <%= yield %>
</body>
</html>

Any code that i want to use for it would go in my ApplicationController since it would be shared across the majority of my app:

 before_filter :generate_user_widget
 def generate_user_widget
   if current_user
     @avatar = ...
     @unread_messages = ...
   end
 end

I understand that it might be cleaner for it to belong in a separate controller BUT honestly, unless the code is huge, it doesn't matter and can even still be put inside a module which is then included by ActionController. However it does need to be inside ApplicationController if you consider the scope of it.

If there are more related pages, say for example, you have a Rails app that manages multiple sites and you want shared behaviour across a particular site, try creating a parent controller which has no actions and only private methods, any controllers that need to have access to those methods can inherit off it. That way you can apply before filters to all controllers which inherit off it, saving you the pain of forgetting to add one in your non-parent controllers.

e.g:

class SiteA::SiteAParentController < ApplicationController
   before_filter :generate_user_widget
   ...
end

class SiteA::ProductController < SiteA::SiteAParentController
  def index
    ...
  end
end
Omar Qureshi