Render content after given block in view helper - ruby-on-rails

I have a view helper method that takes a block. Render that block is no problem, but when I try to add content after the block is rendered, it does not work.
def validation_div(&block)
content_tag :div do
yield
content_tag :div do
'This content is never rendered!'
end
end
end
The above code just yields the block and skips the other content. I have also tried with: content_for, capture, concat and with_output_buffer without any success. As you notice, I don't really understand how these methods work... But my question is: how to render something after the given block is rendered. Thanks!

If you look at a content_tag definition, you see it only outputs one tag, one class, and one content. You're trying to get it out out multiple contents so you'll need to join them.
def validation_div(&block)
content = capture(&block)
content_tag :div do
content + content_tag(:div , "This content is never rendered!")
end
end

Related

How can I yield more than one partial in a block?

I asked a similar question recently, though that was aimed at having multiple blocks as arguments. This problem is a little more immediate.
The problem I have is, I have a helper method which I want to be able to pass content as a block to render. However, if I add more than one partial only the last one in the block is rendered. The methods are below.
def bootrap_panel(title, klass = 'primary', &block)
content_tag(:div, panel_heading(title) + panel_body(&block), class: 'panel panel-' + klass)
end
def panel_body(&block)
content_tag(:div, yield, class: 'panel-body') if block_given?
end
And an example of an issue I am having is here, where only the last partial is being displayed on the page.
=bootrap_panel 'Panels', 'primary' do
- render "dynamic_panels/partials/new"
- render "dynamic_panels/partials/dynamic_panels", dynamic_panels: dynamic_page.dynamic_panels
My first thought is, well I should be yielding the partials to an array or something first, then display that (I am not sure I am able to do that). Secondly, i am using the '-' operator instead of the '=' operator for displaying ruby content in haml. Why?
Pass the block itsef instead of its return value to content_tag:
content_tag(:div, class: 'panel-body', &block)
Other method:
content_tag(:div, capture(&block), class: 'panel-body')

How to differ queries in Ruby helper method

While refactoring I though it'll b great to convert
%p.user-greatings #{gravatar_for #project.user} #{link_to #project.user.name, #project.user}
to helper method in order to follow DRY convention.
My raw helper method:
def assigned_user
gravatar_for yield link_to yield.name, yield
end
And my view:
%p.user-greatings #{assigned_user{#project.user}}
But my "assigned_user" displays only one part:
gravatar_for yield
How to change my method to display both parts in my view?
Calling methods while not adding braces can be confusing. Actually you are calling:
def assigned_user
gravatar_for(yield(link_to(yield.name, yield)))
end
Since your block ignores the parameters passed to it, you get something equivalent to
gravatar_for yield
I'm not sure what you tried to do, and why did you opt to bass a block rather than a simple value:
def assigned_user(user)
"#{gravatar_for user} #{link_to user.name, user}"
end
%p.user-greatings #{assigned_user(#project.user)}

method attributes [ajax,jquery,rails4]

I am reading the book Agile web developpment with rails 4.
there is a part where the products' cart is showing only if it is not empty, my question is the function in the view send to the helper only 2 attributes while in the implementation there are 3 parameters.
in the view I have the bellow code, which render to _cart where I have the cart show
<%= hidden_div_if(#cart.line_items.empty?, id: 'cart') do %>
<%= render #cart %>
<% end %>
the helper has:
module ApplicationHelper
def hidden_div_if(condition, attributes = {}, &block)
if condition
attributes["style"] = "display: none"
end
content_tag("div", attributes, &block) end
end
My question is the &block in this case receives id: 'cart' but is it a optional attibute? that why it comes with &. but what about attributes = {}?
I am really not sure how that is happening, could someone explain me a bit?
Thanks!!
The code between and including do and end is the block, and this is the third argument for hidden_div_if, which is simply passed on to content_tag. The & in the definition of hidden_div_if captures the block in your view, whereas the & in the call to content_tag expands it again to pass it along.
The answer here explains this idea nicely with a few examples. I recommend testing everything out yourself in irb to get a feel for it.

Render ERB as HTML and ERB from a Rails View

I'm making a style guide where I output the code on the right that is displayed on the left.
I know that adding %% escapes ERB
I have written a helper that takes the contents of a block and renders the code in two places one showing the html and I want the other to show the source ERB that created the html.
The problem is I get back HTML where I wanted ERB.
The View Code
<%= display_code do %>
<%= link_to "Button", "/style_guide, class: "btn" %>
<% end %>
The Helper Code
module StyleGuideHelper
def display_code(&block)
content = with_output_buffer(&block)
html = ""
html << content_tag(:div, content, class: "rendered-code")
html << content_tag(:div, escape_erb(content), class: "source-code-preview")
html.html_safe
end
def escape_erb(code)
code = code.gsub("%=", "%%=")
end
end
Expected Result
Button <%= link_to "Button", "/style_guide, class: "btn" %>
Actual Result
Button Button
Cheers
The issue is that this helper runs the block (link_to "Button", ...) -- it never sees the source code inside the block, just its output. You could replace escape_erb with h to capture the resulting HTML, but that won't pop back up to the ERB that generated it.
As I see it, your options are:
Break out examples into partials, then make a helper that a) renders the partial and b) displays the underlying file.
Specify your ERB fragments as strings (heredocs?), pass the string into the helper, and have the helper a) evaluate it via ERB.new(string).result(binding) to render the result and b) display the string.
Make the helper determine what part of the view invoked it, then parse the .erb well enough to find the block. Catch is, the precise format of what you see in callers is subject to change without notice due to the way views are compiled.
Make a helper that uses crazy metaprogramming juju to evaluate the block in both an ERB context as well as your own special context that intercepts the code being evaluated and turns it back into markup.
...sorted in approximate order of complexity and odds of success.
This code below will allow you to retrieve the code for a given block.
class ERBSource
ERB = ::ActionView::Template::Handlers::ERB
def self.for(block)
new(block).source
end
attr_reader :block, :file, :line_number
def initialize(block)
#block = block
#file, #line_number = *block.source_location
end
def source
lines = File.readlines(file)
relevant_lines = lines[(line_number - 1)..-1] || []
extract_first_expression(relevant_lines)
end
private
def extract_first_expression(lines)
code = lines.slice[0,1].join # add the first two lines so it has to iterate less
lines.each do |line|
code << line
return code if correct_syntax?(compile_erb(code))
end
raise SyntaxError, "unexpected $end"
end
def correct_syntax?(code)
stderr = $stderr
$stderr.reopen(IO::NULL)
RubyVM::InstructionSequence.compile(code)
$stderr.reopen(stderr)
true
rescue Exception
$stderr.reopen(stderr)
false
end
def compile_erb(code)
ERB.erb_implementation.new(
code,
:escape => false,
:trim => (ERB.erb_trim_mode == "-")
).src
end
end
This is what the helper looks like
module StyleGuideHelper
def render_example(name, &block)
code = ERBSource.for(block)
content_tag(:h2, name) +
content_tag(:div, &block) +
content_tag(:pre, content_tag(:code, code))
end
end

Rails: What's the difference between capture and content_for?

In the Rails 3.2 CaptureHelper, what are the differences between using capture and content_for, and why would I choose one over the other?
If you check out the content_for source, it calls capture internally:
def content_for(name, content = nil, &block)
if content || block_given?
content = capture(&block) if block_given?
#view_flow.append(name, content) if content
nil
else
#view_flow.get(name)
end
end
So, from reading through the method, it looks like the primary advantage of content_for is that it can be called multiple times with multiple blocks for the same named content and each additional call will just append onto whatever has already been rendered. Whereas, in the case of capture, if you call:
<% #greeting = capture do %>
Hello
<% end %>
and then later call:
<% #greeting = capture do %>
Or, in espanol, Hola
<% end %>
Then the last part is the only part that will be captured, and the 'Hello' will just be discarded. Whereas, doing something similar in content_for will result in the second call being appended to 'Hello'.

Resources