20

I'm attempting to post a random testimonial on each page of a site.

I started off by using an application helper like this:

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.

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 Answers 2

50

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.

Sign up to request clarification or add additional context in comments.

5 Comments

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.
This is really old I know, but this isn't correct. The View in MVC can QUERY the model, it just can't MANIPULATE it. View Helpers, therefore, can inquire the model state independently of controllers.
@sunwukung Actually this post is correct. Too often Rails VIEW helpers become a dumping ground for procedural business logic. The point here is SOC. The view should not be instantiating models, nor should it contain model behaviour.
@azriel - neither of which I'm suggesting. The role of view helpers is formatting, as stated - but the V in MVC is permitted to 'observe' the model, and as such can make queries (not updates) on the model to achieve this. Folks see the C as the fence between the M and the V
@sunwukung This is not querying the model's state. It is creating a new instance of the model based on some business logic. In fact, in the original code, the view is determining the state of the model.
6

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.