views:

3461

answers:

3

I'm attempting to post a random testimonial on each page of a site. I started off by using an application helper like so:

module ApplicationHelper

  def random_testimonial
    @random_testimonial = Testimonial.find(:first, :offset => rand(Testimonial.count))
  end

end

In my view, I can reference the method but it's being called on each reference, which makes sense. Instead, I'd like this to be called once on each page view, exposing a Testimonial object I can use within the view. What should I be looking for to do this?

+2  A: 

If I understand you correctly, you want a method that returns the same object every time it is referenced in one request/response cycle. If this is true, you can achieve it with a minor change to your helper:

 def random_testimonial
    @random_testimonial ||= Testimonial.find(:first, :offset => rand(Testimonial.count))
 end

Notice the "||=" part. That's a Ruby idiom which says: assign a value to @random_testimonial, unless it already has a value.

Hope that answers your question.

Milan Novota
Sometimes I'm not sure about Ruby, but that is really cool.
Dave Ray
A: 

Thank you, that did the trick!

Chris Stewart
+9  A: 

While that works, and I have certainly been known to do this, it violates the MVC separation of concerns. View helpers are not supposed to contain controller/model type logic, which this does.

You might consider refactoring this back into the application controller. Helpers are supposed to be for view formatting and stuff, more than as a function (which is what I kept wanting to do when I got started.)

If you got back into your Testimonail model, do could do

def self.random
  Testimonial.find(:first, :offset => rand(Testimonial.count))
end

then in your application controller, you could do:

def random_testimonial
  @random_testimonial ||= Testimonial.random
end

and call it from a before_filter

This has the advantage of moving the database logic back into the model where it belongs.

Scott Miller
Agreed. Voted up your solution, Scott. Chris, I'd recommend you to select Scott's answer as a correct one. I was too focused on the problem of caching the variable and missed this obvious flaw in the design.
Milan Novota