{"id":2987,"date":"2012-07-27T15:24:07","date_gmt":"2012-07-27T18:24:07","guid":{"rendered":"http:\/\/blog.plataformatec.com.br\/?p=2987"},"modified":"2012-07-28T23:23:29","modified_gmt":"2012-07-29T02:23:29","slug":"flushing-content-blocks-with-rails-4","status":"publish","type":"post","link":"https:\/\/blog.plataformatec.com.br\/2012\/07\/flushing-content-blocks-with-rails-4\/","title":{"rendered":"Flushing content blocks with Rails 4"},"content":{"rendered":"
Besides the big and shiny features that Rails 4 holds, there’s a lot of small improvements on several other sections of the Rails framework – helpers, core extensions, app configurations and more – that might not even hit the Changelogs but will somehow make our lifes easier in the future. One of these hidden gems that I’ve found recently is an improvement on the The Multiple calls of the On some scenarios this behavior might not be desired, and with Rails 4 you can flush out the stored pieces of an identifier and replace it instead of adding more content to it: using the I’ve stumbled upon this on a recent project, where we had a somewhat classic scenario: a partial named It works like a charm. But with an updated requirement we had the case where multiple galleries could be present on the same page, rendering the Well, while this seems to be a perfect solution to my problem, this feature isn’t available on Rails 3.2 or on the After some source diving into the ActionPack source code we’re done – it just needs to replace any present content with a brand new What do you think about this little addition to Rails 4? Can you think of a similar problem that could be solved with this instead of a custom hack?<\/p>\n","protected":false},"excerpt":{"rendered":" Besides the big and shiny features that Rails 4 holds, there’s a lot of small improvements on several other sections of the Rails framework – helpers, core extensions, app configurations and more – that might not even hit the Changelogs but will somehow make our lifes easier in the future. One of these hidden gems … \u00bb<\/a><\/p>\n","protected":false},"author":17,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"ngg_post_thumbnail":0,"footnotes":""},"categories":[1],"tags":[186,92,176],"aioseo_notices":[],"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/posts\/2987"}],"collection":[{"href":"https:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/users\/17"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/comments?post=2987"}],"version-history":[{"count":20,"href":"https:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/posts\/2987\/revisions"}],"predecessor-version":[{"id":3011,"href":"https:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/posts\/2987\/revisions\/3011"}],"wp:attachment":[{"href":"https:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/media?parent=2987"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/categories?post=2987"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/tags?post=2987"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}content_for<\/code> helper to flush and replace previous chunks of HTML with new ones.<\/p>\n
The
content_for<\/code> that we are used to<\/h3>\n
content_for<\/code> method is an old friend of every Rails developer, and it’s a pretty simple and flexible helper. You can store a chunk of HTML from a String or a block, and grab it somewhere else in your views or
yield<\/code> it directly into your templates. It’s a pretty handy trick to move data from your views into your layouts, like page titles, custom meta tags or specific
script<\/code> tags that your page needs to include.<\/p>\n
\n# On your 'application.html.erb' layout, inside the '' tag.\n<%= yield :metatags %>\n\n# Then, into a specific view\n<% content_for :metatags do %>\n \n<% end %>\n<\/pre>\n
content_for<\/code> helper using the same identifier will concatenate them and output them together when you read it back on your views, as:<\/p>\n
\n<% content_for :example, \"This will be rendered\" %>\n<% content_for :example do %>\n
This will be rendered too!<\/h1>\n<% end %>\n<\/pre>\n
flush: true<\/code> option. The first implementation<\/a> used an extra
true<\/code> argument, but we changed<\/a> to use a Hash instead, so the
flush<\/code> key can express better the behavior we’re expecting.<\/p>\n
\n<% content_for :example, \"This will be rendered\" %>\n<% content_for :example, flush: true do %>\n
But this will override everything on the ':example' block.<\/h1>\n<% end %>\n<\/pre>\n
The gallery situation<\/h3>\n
_gallery<\/code>, responsible for rendering the piece of HTML to display a gallery of images that also supplies a
content_for<\/code> block with a
script<\/code> tag to include the required libraries to put the gallery to work.<\/p>\n
\n
_gallery<\/code> partial several times. The required HTML would be present, but the
gallery.js<\/code> script would be included multiple times into the rendered page. Instead of working this out using instance variables to check that the partial was rendered at least once, we could let Rails do all the hard work for us, using the
flush<\/code> option when including the
gallery.js<\/code> script.<\/p>\n
\n
Back to the present: Rails 3.2<\/h3>\n
3-2-stable<\/code> branch – it’s only available on the
master<\/code> branch that will be released with Rails 4. But, backporting this feature into a 3.x application is pretty simple, using a helper of your own.<\/p>\n
\ndef single_content_for(name, content = nil, &block)\n @view_flow.set(name, ActiveSupport::SafeBuffer.new)\n content_for(name, content, &block)\nend\n<\/pre>\n
SafeBuffer<\/code> instance before storing the piece of HTML.<\/p>\n