Module: Sinatra::ContentFor
Relationships & Source Files | |
Super Chains via Extension / Inclusion / Inheritance | |
Instance Chain:
self,
Capture ,
EngineTracking
|
|
Defined in: | sinatra-contrib/lib/sinatra/content_for.rb |
Overview
Sinatra::ContentFor is a set of helpers that allows you to capture blocks inside views to be rendered later during the request. The most common use is to populate different parts of your layout from your view.
The currently supported engines are: Erb, Erubi, Haml and Slim.
Usage
You call #content_for, generally from a view, to capture a block of markup giving it an identifier:
# index.erb
<% content_for :some_key do %>
<chunk of="html">...</chunk>
<% end %>
Then, you call #yield_content with that identifier, generally from a layout, to render the captured block:
# layout.erb
<%= yield_content :some_key %>
If you have provided #yield_content with a block and no content for the specified key is found, it will render the results of the block provided to yield_content.
# layout.erb
<% yield_content :some_key_with_no_content do %>
<chunk of="default html">...</chunk>
<% end %>
Classic Application
To use the helpers in a classic application all you need to do is require them:
require "sinatra"
require "sinatra/content_for"
# Your classic application code goes here...
Modular Application
To use the helpers in a modular application you need to require them, and then, tell the application you will use them:
require "sinatra/base"
require "sinatra/content_for"
class MyApp < Sinatra::Base
helpers Sinatra::ContentFor
# The rest of your modular application code goes here...
end
And How Is This Useful?
For example, some of your views might need a few javascript tags and
stylesheets, but you don't want to force this files in all your pages.
Then you can put <%= yield_content :scripts_and_styles
%> on your
layout, inside the
Limitations
Due to the rendering process limitation using <%= yield_content %> from within nested templates do not work above the <%= yield %> statement. For more details https://github.com/sinatra/sinatra-contrib/issues/140#issuecomment-48831668
# app.rb
get '/' do
erb :body, :layout => :layout do
erb :
end
end
# foobar.erb
<% content_for :one do %>
<script>
alert('one');
</script>
<% end %>
<% content_for :two do %>
<script>
alert('two');
</script>
<% end %>
Using <%= yield_content %> before <%= yield %> will cause only the second alert to display:
# body.erb
# Display only second alert
<%= yield_content :one %>
<%= yield %>
<%= yield_content :two %>
# body.erb
# Display both alerts
<%= yield %>
<%= yield_content :one %>
<%= yield_content :two %>
Instance Attribute Summary
EngineTracking
- Included
#builder?, #current_engine, #erb?, | |
#erubi? | Returns true if the current engine is |
#haml?, #liquid?, #markaby?, #markdown?, #nokogiri?, #rdoc?, #ruby?, #sass?, #scss?, #slim? |
Instance Method Summary
-
#clear_content_for(key)
Unset a named block of content.
-
#content_for(key, value = nil, options = {}, &block)
Capture
a block of content to be rendered later. -
#content_for?(key) ⇒ Boolean
Check if a block of content with the given key was defined.
-
#yield_content(key, *args, &block)
Render the captured blocks for a given key.
- #content_blocks private
Capture
- Included
EngineTracking
- Included
Instance Method Details
#clear_content_for(key)
Unset a named block of content. For example:
<% clear_content_for :head %>
# File 'sinatra-contrib/lib/sinatra/content_for.rb', line 155
def clear_content_for(key) content_blocks.delete(key.to_sym) if content_for?(key) end
#content_blocks (private)
[ GitHub ]# File 'sinatra-contrib/lib/sinatra/content_for.rb', line 191
def content_blocks @content_blocks ||= Hash.new { |h, k| h[k] = [] } end
#content_for(key, value = nil, options = {}, &block)
Capture
a block of content to be rendered later. For example:
<% content_for :head do %>
<script type="text/javascript" src="/foo.js"></script>
<% end %>
You can also pass an immediate value instead of a block:
<% content_for :title, "foo" %>
You can call content_for
multiple times with the same key
(in the example :head
), and when you render the blocks for
that key all of them will be rendered, in the same order you
captured them.
Your blocks can also receive values, which are passed to them by yield_content
# File 'sinatra-contrib/lib/sinatra/content_for.rb', line 132
def content_for(key, value = nil, = {}, &block) block ||= proc { |*| value } clear_content_for(key) if [:flush] content_blocks[key.to_sym] << capture_later(&block) end
#content_for?(key) ⇒ Boolean
Check if a block of content with the given key was defined. For example:
<% content_for :head do %>
<script type="text/javascript" src="/foo.js"></script>
<% end %>
<% if content_for? :head %>
<span>content "head" was defined.</span>
<% end %>
# File 'sinatra-contrib/lib/sinatra/content_for.rb', line 148
def content_for?(key) content_blocks[key.to_sym].any? end
#yield_content(key, *args, &block)
Render the captured blocks for a given key. For example:
<head>
<title>Example</title>
<%= yield_content :head %>
</head>
Would render everything you declared with content_for :head before closing the tag.
You can also pass values to the content blocks by passing them as arguments after the key:
<%= yield_content :head, 1, 2 %>
Would pass 1 and 2 to all the blocks registered for :head.
# File 'sinatra-contrib/lib/sinatra/content_for.rb', line 176
def yield_content(key, *args, &block) if block_given? && !content_for?(key) haml? && Tilt[:haml] == Tilt::HamlTemplate && respond_to?(:capture_haml) ? capture_haml(*args, &block) : yield(*args) else content = content_blocks[key.to_sym].map { |b| capture(*args, &b) } content.join.tap do |c| if block_given? && (erb? || erubi?) @_out_buf << c end end end end