Beginner Layouts and Partials question

Hello - very new to rails and MVC, I’m trying to figure out how
layouts/partials co-exist. My basic layout (application.html.erb) looks
like this:

<%= render :partial => "main/header" %>
<%= render => :partial => "main/menu" %> <%= render => :partial => @partial %>

and my MainController is:

class MainController

def index
@partial = “main/home”
end

end

Now, I found that I have to create an index.html.erb file that’s
identical to the application.html.erb file, or nothing works (neither
can exist without the other). I’m trying to understand what I’m doing
wrong – obviously I need some index action in my controller, but I’d
like to just maintain one layout file and nothing else… I’m obviously
missing something big here, so any clarifications will be great :slight_smile:

right: you need an index-file for your index-action (actions and views
pair up)
wrong: it has not to be identical to the layout-file.

try to put
<%= yield %>
into your layout instead of
<%= render => :partial => @partial %>
and change your index to
Hello it’s <%= Time.now %>

in your controller just leave it like this
def index
end

now, if you want to render a partial, do so by saying it for example
in your view. if you put
render :partial => foo
in your controller, then by default
layout => false
is set.

maybe i’m even mistaken somewhere, but anyhow i hope i could help. my
suggestion: get hold of some rails basics.

Here it goes…

A layout is like the container for the content(… view) relating to
your actions. When an action is called, the action renders its view.
For example, the person controllers index action will look for app/
views/person/index.html.erb. It also looks for the layout it should
render the view in. You can define the layout to use either in the
controller (layout ‘application’ in your case) or put in in
application.rb, which will then define a global default layout.

You’ve got the right idea with the erb you posted. You can render
partials in layouts, but for the action to render it’s view in the
layout, you need to put <%= yield %>. The entire contents of the
actions’s view will get rendered there.

Your layout, application.html.erb should be residing in the app/views/
layout directory. You should add “layout ‘application’” to your
controller, add <%= yield %> to the layout, create views for your
actions and try it out. Your views should render inside your layout.

I hope that gives you some idea of how views and layouts interact.

  • John

Those were really helpful posts – I think I got the general idea, in
which I should specify in the controller which layout it should belong
to, and then in the layout file use <%= yield %> to render these views.
I’ll keep playing with it and see what comes up.

Thanks!

sa 125 wrote:

Those were really helpful posts – I think I got the general idea, in
which I should specify in the controller which layout it should belong
to, and then in the layout file use <%= yield %> to render these views.
I’ll keep playing with it and see what comes up.

Thanks!

Take this example:

app/controllers/people_controller.rb:

class PeopleController < ApplicationController

layout ‘custom’

GET /people

GET /people.xml

def index
@people = Person.find(:all)

respond_to do |format|
  format.html # index.html.erb
  format.xml  { render :xml => @people }
end

end
end

app/views/layouts/application.html.erb:

My Application

Header in Application layout

<%= yield %>

Footer in layout

app/views/layouts/people.html.erb:

My Application

Header in People layout

<%= yield %>

Footer in layout

----

app/views/layouts/custom.html.erb:

My Application

Header in Custom layout

<%= yield %>

Footer in layout

----

app/views/people/index.html.erb:

Listing people

<% for person in @people %>
<%= render :partial => ‘list’ %>
<% end %>

First name Last name

<%= link_to ‘New person’, new_person_path %>

Notice in this example that the first line in the people_controller is
commented out. So in this case Rails begins searching for an appropriate
layout by first looking in app/layouts/ for a layout template named
people.html.erb. If it exists Rails will use it automatically. If it
does not exist then Rails looks for a template named
application.html.erb. If that file exists it will be applied to any
controller that does not specify a specific layout to use.

In all cases if the layout is provided (by uncommenting line #1 in this
example controller) it will look for a template with the given name
(custom.html.erb) in this example.

I also provided a contrived partial in the
app/views/people/index.html.erb template to show when how how partials
might be used.

There is also a method called “content_for” I’ll leave that up to you to
investigate, but this can also be very useful when dealing with layouts
and partials.

Robert W. wrote:

layout by first looking in app/layouts/ for a layout template named

Correction app/views/layouts/

You may also want to read the getting started guide (and others) on
http://guides.rubyonrails.org

Ryan B.
Freelancer

I realize the partial doesn’t recognize the person object, but I thought
rails handled the conversion between the collection @people of the view
to the iteration in the partial. So… I’m not sure what I might be doing
wrong. Help is very appreciated - thanks!

i don’t see an iteration. try

for person in people do
<tr class=<%= cycle(“odd”,“even”)%>>

<%= h person.first_name %>
<%= h person.last_name %>

end

in the view (app/views/people/index.html.erb):

<% content_for :title do -%>

Listing People

<% end -%> <%= render :partial => "people", :collection => @people %>
First Name Last Name

in the partial (app/views/people/_people.html.erb):

> <%= h person.first_name %> <%= h person.last_name %>

I made sure I had data available for these people (using
script/console), but I got an error rendering this partial:

undefined local variable or method ‘person’ for #ActionView::....

in app/views/people/_people.html.erb

OK, I figured out my mistake - when creating the partial, I called it
“_people.html.erb” instead of “_person.html.erb”, so the rails engine
probably didn’t know what to look for. Also needed to change the call to
render from <%= render :partial => “people” …%> to <%= render
:partial => “person”…%>

I would like to know how to override this behavior so that I could call
the partial and the collections however I want. Thanks to everyone who
helped on this post!

These were all really helpful – I really appreciate the depth of the
responses. I now only have a problem with using a collection in
rendering a partial. I think I followed the exact rules, but here is
what I did anyway:

The layout (app/views/layouts/application.html.erb):

<%= yield :title %>
<%= yield %> ...

the controller (app/controllers/people/people_controller.rb):

class PeopleController < ApplicationController
layout “application” # default, but specified anyway
def index
@people = Person.find(:all)
end
end

in the view (app/views/people/index.html.erb):

<% content_for :title do -%>

Listing People

<% end -%> <%= render :partial => "people", :collection => @people %>
First Name Last Name

in the partial (app/views/people/_people.html.erb):

> <%= h person.first_name %> <%= h person.last_name %>

I made sure I had data available for these people (using
script/console), but I got an error rendering this partial:

undefined local variable or method ‘person’ for #ActionView::....

in app/views/people/_people.html.erb

I realize the partial doesn’t recognize the person object, but I thought
rails handled the conversion between the collection @people of the view
to the iteration in the partial. So… I’m not sure what I might be doing
wrong. Help is very appreciated - thanks!

sa 125,

This paper (Modular Page Assembly in Rails) helps a lot:

http://www.railsdev.ws/blog/3/modular-page-assembly-in-rails/

Cheers, Sazima