Dave Collins
Dave Collins

Reputation: 1087

Is there a more elegant way? (accessing a rails controller from a static home page?)

OK, this is working but I feel there is a better way to do this in Rails... I have a home page which, if you have not signed in, is not currently pulling in anything from any model or controller. It exists at /pages/home.html.erb

On that page, I want to grab the next party from my Parties model and tell the website visitor about that party. Easy enough, right?:

/app/controllers/parties_controller.rb

def nextparty
  @party = Party.find(:first, :order => "begins_on")
end

Now, in my home page, I used this and it works fine:

/app/views/pages/home.html.erb

<% @PartyCont = PartiesController.new() %>
<% @party = @PartyCont.nextparty() %>
<h3>The next party is <%= @party.name %></h3>

I tried helper methods, partials, ApplicationHelper, but this was the only code that actually worked. Most of the other things I tried seemed to fail because the @Party class was not instantiated (typically the error indicated the class with a temporary name and "undefined method").

Hey, I'm happy that it works, but I feel like there is a better way in Rails. I've seen a few posts that use code like the above example and then say "But you really shouldn't ever need to do this!".

Is this just fine, or is there a more Rails-like way?

UPDATE: I think the problem is more than just elegance... I just realized that all RSPEC tests that hit the home page are failing with:

Failure/Error: get 'home'
 ActionView::Template::Error:
  undefined method `begins_on' for nil:NilClass

Thanks!

Upvotes: 0

Views: 84

Answers (2)

ajmurmann
ajmurmann

Reputation: 1635

Your view should only show data that already was made available by your controller. You want to display a party resource, so the request should go to the parties controller. If I understand your use case correctly, than more specifically to the index method on the PartiesController.

There you should have the following code:

def index
  @party = Party.find(:first, :order => "begins_on")
end

That instance method will be available in your corresponding view app/views/parties/index.html.erb

<h3>The next party is <%= @party.name %></h3>

To make this available as your homepage you will have to adjust your route as well: config/routes.rb

root :to => "parties#index"

Your view should contain as little logic as possible and mainly be concerned with how things look. Your controller should get data for the view ready and make sure to call the right method on the model. All the heavy business logic should be in your model.

I think you should work through a basic introductory Rails tutorial.

Upvotes: 0

Tom L
Tom L

Reputation: 3409

You want a controller behind every view and you don't want views crossing controller boundaries in order to present information. Consider having a welcome controller (or whatever you prefer to call it). It can have an index action:

def index
  @party = Party.find(:first, :order => "begins_on")
end

In config/routes.rb, make it the root controller action:

root :to => "welcome#index"

Also, to DRY that up add a .nextparty class method to the Party model and call that from both of your controller actions instead of the find method.

Upvotes: 2

Related Questions