Topic: Another DRY controller question

Greetings All

My client wants a list of all the products in the right column of his website to be visible at all times. Is there a way of DRYing my static page controller up?

class PagesController < ApplicationController
  layout "application"

  def index
    ...
    @products = Product.find(:all, :order=>"name ASC")
  end

  def about
    ...
    @products = Product.find(:all, :order=>"name ASC")
  end

  def services
    ...
    @products = Product.find(:all, :order=>"name ASC")
  end

  def contact
    ...
    @products = Product.find(:all, :order=>"name ASC")
  end
end


Thanx in advance

Re: Another DRY controller question

class PagesController < ApplicationController
  layout "application"

  before_filter :get_all_products

  def index
    ...
  end

  def about
    ...
  end

  def services
    ...
  end

  def contact
    ...
  end

private
def get_all_products
  @products = Product.find(:all, :order=>"name ASC")
end
end


If you want to use this in all Controllers, add the filter & Method to ApplicationController instead.

Last edited by Duplex (2007-08-27 07:23:00)

Re: Another DRY controller question

DUDE!!! You're a frikken genius!!!

Thanx a lot

Re: Another DRY controller question

Are you just rendering the list of products in the side bar or layout or something? In that case I don't think this code belongs in a controller before filter. Instead I recommend putting it in a helper.

# on any page
<%= list_products %>

# in application_helper.rb
def list_products
  products = Product.find(:all, :order=>"name ASC")
  render :partial => 'pages/products', :object => products
end


Then you just need the pages/_products.rhtml partial to handle the HTML.

Railscasts - Free Ruby on Rails Screencasts

Re: Another DRY controller question

Ryan, I thought it was taboo to to retrieve model objects in views/helpers? I've been taught that the controller is what retrieves model objects and feeds them to the view. I'm not nearly as experienced as you, can you please explain your thinking behind putting this code in a helper? My first thought was to put the code in a module; is there something wrong with that? Thanks!

Re: Another DRY controller question

The MVC paradigm doesn't restrict views from accessing models directly. Views have as much access to models as controllers do. In fact, the logic of that find should go in the model behind a "find_alphabetical" method or something. It doesn't belong in the controller just as much as the view.

But anyway, back on topic. The role of the controller is to handle the user input (request) and spit out a response. The controller should take the request and turn it into variables for the view to use. For example, if the user is performing a keyword search on products, it is the controllers job to take the search parameters and put the list of products in a variable for the view to display.

In this case, however, the request has nothing to do with products. It is not dependent on user input and is not the primary focus of the page, it is just a little extra thing on the side.

The problem with putting it in the controller is separation of concern. If you want to add the list of products to another page, or take it away from a page, you need to remember to go back into the controller and adjust the before filter. This feels wrong. Placing it in a helper which calls a partial solves this issue and makes it self contained.

Railscasts - Free Ruby on Rails Screencasts

Re: Another DRY controller question

That is an awesome explanation. It will put many things in a new light for me. Thanks!

Re: Another DRY controller question

I am still learning the MVC paradigm so just a quick question to ryanb's explanation.

I thought I had read that instance variables created in the model were not visible to the view.

Re: Another DRY controller question

GeekyG wrote:

I thought I had read that instance variables created in the model were not visible to the view.

In the model, yes. However instance variables created in the controller are available to the view.

Railscasts - Free Ruby on Rails Screencasts

Re: Another DRY controller question

The MVC paradigm doesn't restrict views from accessing models directly. Views have as much access to models as controllers do.

I don't want to steer this thread off course, but I have been wondering about this topic.

1. If the view can't see model instance variables, how does the view access the model?

2. I have read where the suggested rails idiom is for a thin controller and to put the majority of logic in the model. Won't the instance variables have to be created in the controller and accessed by the model so that the result is displayed in the view? Seems this could be contrary to the thin controller and possibly not very DRY?

Thanks for the reply ryanb. I am amazed at your volume of posts.

Re: Another DRY controller question

GeekyG wrote:

1. If the view can't see model instance variables, how does the view access the model?

Not sure what you're asking here. Controllers, views, or other models don't have access to a given model's instance variables. That's how encapsulation works in object oriented programming: an object doesn't have access to the internals of another object. However, you can provide accessor methods for fetching and manipulating that data. In that case the methods can be called from the controller, view, or any other object.

GeekyG wrote:

2. I have read where the suggested rails idiom is for a thin controller and to put the majority of logic in the model. Won't the instance variables have to be created in the controller and accessed by the model so that the result is displayed in the view? Seems this could be contrary to the thin controller and possibly not very DRY?

You should put as much logic in the model as you can, yes. A model can't access a controller's instance variables, they are completely separate. Perhaps what's confusing is the fact that a controller's instance variables are shared with the view. This is not normal since they are two separate objects, but Rails does some magic here for the sake of convenience.

Railscasts - Free Ruby on Rails Screencasts