I've come to appreciate the "skinny controllers" philosophy in Rails that says that business logic should not be in controllers, but that they should basically only be responsible for calling a few model methods and then deciding what to render/redirect. Pushing business logic into the model (or elsewhere) keeps action methods clean (and avoids stubbing long chains of ActiveRecord methods in functional tests of controllers).
Most cases I've run across are like this: I have three models, Foo, Bar, and Baz. Each of them has a method or scope defined (call it filter) that narrows down the objects to what I'm looking for. A skinny action method might look like:
def index
@foos = Foo.filter
@bars = Bar.filter
@bazs = Baz.filter
end
However, I've run into a case where the view needs to display a more hierarchical data structure. For example, Foo has_many bars and Bar has_many bazs. In the view (a general "dashboard" page), I'm going to display something like this, where each foo, bar, and baz has been filtered down with some criteria (e.g. for each level I only want to show active ones):
Foo1 - Bar1 (Baz1, Baz2)
Bar2 (Baz3, Baz4)
-----------------------
Foo2 - Bar3 (Baz5, Baz6)
Bar4 (Baz7, Baz8)
To provide the view with the data it needs, my initial thought is to put something crazy like this in the controller:
def index
@data = Foo.filter.each_with_object({}) do |foo, hash|
hash[foo] = foo.bars.filter.each_with_object({}) do |bar, hash2|
hash2[bar] = bar.bazs.filter
end
end
end
I could push that down to the Foo model, but that's not much better. This doesn't seem like a complex data structure that merits factoring out into a separate non-ActiveRecord model or something like that, it's just fetching some foos and their bars and their bazs with a very simple filter applied at each step.
What is the best practice for passing hierarchical data like this from a controller to a view?