Bruce
Bruce

Reputation: 1678

Ruby on Rails: provide vs content_for

I came across the view helper function "provide" today. By looking into its manual I am still confused on how it is different from "content_for".

provide(name, content = nil, &block)

The same as content_for but when used with streaming flushes straight back to the layout. In other words, if you want to concatenate several times to the same buffer when rendering a given template, you should use content_for, if not, use provide to tell the layout to stop looking for more contents.

Question 1: this is quite abstract to me - could anyone flesh it out by giving a demonstrative example?

Question 2: working with asset pipeline, which performs better and why?

Thanks!

Upvotes: 31

Views: 7773

Answers (2)

rodamn
rodamn

Reputation: 2211

First of all, what is streaming? Why would you use it?

Streaming is alternate method of rendering pages top-down (outside-in). The default rendering behavior is inside-out. Streaming must be enabled in your controller:

class MyController
  def action
    render stream: true # Streaming enabled
  end
end

According to the documentation:

Streaming may be considered to be overkill for lightweight actions like new or edit. The real benefit of streaming is on expensive actions that, for example, do a lot of queries on the database.

So, if you're not using streaming, is there still a difference?

Yes.

The difference is a template can define multiple content blocks by calling content_for multiple times. Doing so will concatenate the blocks and pass that to the layout:

# layout.html.erb
<div class="heading"><%= yield :surprise %></div>
<div class="body">
   <p><%= yield %></p>
   <p>But it's not very interesting...</p>
</div>

# template.html.erb
<%= content_for :surprise, "Hello" %>
I've got your content!
<%= content_for :surprise, ", World!" %>

# Generated HTML
<div class="heading">Hello, World!</div>
<div class="body">
   <p>I've got your content!</p>
   <p>But it's not very interesting...</p>
</div>

Since provide doesn't continue searching the provided template, only the block passed to the first provide call will be sent to the template:

# layout.html.erb
<div class="heading"><%= yield :title %></div>

# template.html.erb
<%= provide :title, "Foo" %>
<%= provide :title, "bar" %>

# Generated HTML
<div class="heading">Foo</div>

Upvotes: 29

rtfminc
rtfminc

Reputation: 6363

Was curious to see what the difference was, and as Thong Kuah pointed to the api, inside the answer:

This means that, if you have yield :title in your layout and you want to use streaming, you would have to render the whole template (and eventually trigger all queries) before streaming the title and all assets, which kills the purpose of streaming. For this reason Rails 3.1 introduces a new helper called provide that does the same as content_for but tells the layout to stop searching for other entries and continue rendering.

Upvotes: 7

Related Questions