When I'm in irb and I do something like this:
node_list.each_element { |e| puts e.text }
It works and prints one line of text per element returned (plus I think it returns the xml object). However, when I head over to rails and have things moving between controllers, helpers, views and layouts it just dumps the xml object.
I should mention that for good reasons I'm using rails 1.2.3 and ruby 1.8.7.
Gratzi!
So the issue your having is that puts writes to console and not the template. Also, in ruby the a method will return by default its last object. So your method as written will loop through #child1, print each's text to the console, and then return the #child1 object at which point your erb tags of <%= %> tells it print the object (#child1 in this case)
You have two options, either you can move it out into the template:
<% tol_get_names(#child1) do |e| %> #note just <% and not <%=
<%= e.text %>
<% end %>
Or build your method so that it loops through building a string and then returns that string instead of the original object:
def tol_get_names(child)
texts = [] #empty array for all our values
child.each_element { |e|
texts << e.text #add the text string to our array
end
texts.join(", ") #build a string and seperate it with a comma
end
Several ways you could write this type of method, but this is my usual way.
Related
In my user profile view I have this:
#show.html.haml
%p
%b Categories
= list_self_reviews(current_user.self_reviews)
The list_self_reviews helper looks like this:
#profiles_helper.rb
def list_self_reviews(reviews)
self_reviews = {}
reviews.each { |review| self_reviews["#{review.get_category_name}"] = "#{review.body}" }
self_reviews.each do |key, value|
puts "#{key} (#{value})"
end
end
I'm creating a hash of review category names and the body of the review and trying to print them in the profile view in the format "[Category Name]: [Review Body]." However, in the view the entire hash is being printed out, so that it looks like this:
{"organizing"=>"I'm a pretty organized guy", "tutoring"=>"helped with spanish"}
It should just say "organizing: I'm a pretty organized guy" and then the other one below it. What am I missing here about how to return this correctly in the view?
Change your profile view file(show.html.haml) as follows
%p
%b Categories
- current_user.self_reviews.each do |review|
= "[#{review.get_category_name}]: [#{review.body}]."
%br/
It's what gets returned from the method that's important - that's what gets inserted into your HTML. puts is for outputting to the console only. Your method is implicitly returning the self_reviews hash because it is the last thing evaluated (with self_reviews.each). As it currently stands, you need to build a single string with all your list items (would likely need to contain HTML) and return that instead.
That being said, I feel like your code could be made neater with something like:
#show.html.haml
%p
%ul Categories
- current_user.self_reviews.each do |review|
%li = review_item(review)
#profiles_helper.rb
def review_item(review)
"#{review.get_category_name}: #{review.body}"
end
...or even no helper at all (like the other answer).
Edit - or you could do something like this:
#show.html.haml
%p
= review_list
#profiles_helper.rb
def review_list
content_tag :ul, "Categories" do
current_user.self_reviews.each do |review|
content_tag :li, "#{review.get_category_name}: #{review.body}"
end
end
end
but personally I prefer my template to be a bit more explicit, and you might be better off using a partial in this case.
Let's say I've got the variable #var. Usually I would use <%= #var %> to write it into the view. Now I want to call a module method from within my view which internally decides to write the content of #var or not.
Inside the module I can't use <%= %>. How can I print the content of #var from within the module? The method would be called like this: <% my_method %>. Thanks
Update
Thanks for the answers so far. Maybe I should say more about my initial problem to be more clear. Sorry if I wasn't clear enough.
At first I used the <%= %> tag like this:
def print_if_present(var)
var ? var : ""
end
<%= print_if_present var %>
But then, when the var was nil, I got "" as output, which took space in the view. How can I prevent this behavior?
I assume that your module is actualy the view helper. If is that so, simply return var.
def my_method
if my_condition
#var
else # else clause is optional
#other_var
end
end
Note that the else clause is optional. If you want to write something or nothing, you can simply use the if. This is so because if the if is not executed and there is no else, it will return nil, that will be casted to an empty string in your template. Just to ilustrate,
if true
1
end
=> 1 #return if last value
if false
1
end
=> nil # return nil because there is no else block
Since you still want to print the return of your method on your template, you need to keep the equal sign:
<%= my_method %>
The best way to do this is to have your method return the string and use <%= ... %> as in fotanus’ answer, but in Rails if you really need to write output directly from a helper you could use the concat method:
The preferred method of outputting text in your views is to use the <%= “text” %> eRuby syntax. The regular puts and print methods do not operate as expected in an eRuby code block. If you absolutely must output text within a non-output code block (i.e., <% %>), you can use the concat method.
So you can define a helper like this:
def my_method
if some_condition
concat "Something or other"
else
concat "Something else"
end
end
And then use it in a non-output block:
<% my_method %>
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
I have a pair of Rails helpers, one of which is meant to accept a block and the other of which just renders a button. Here are simplified versions the helper definitions:
def nav_wrapper(nav_at, id, css_class, &block)
"<ul class="complicated">\n #{yield} \n</ul>".html_safe
end
def nav_btn(nav_at, caption, id = caption.downcase.dasherize)
"Nav button codes goes here".html_safe
end
I'm trying to set things up such that I can do something like this:
<%= nav_wrapper(#nav_at, "Top Nav", "class") do %>
<%= nav_btn(#nav_at, "Foo", "id") %>
<%= nav_btn(#nav_at, "Bar", "id") %>
<%= nav_wrapper(#nav_at, "Sub Nav", "class") do %>
<%= nav_btn(#nav_at, "SubFoo", "id") %>
<%= nav_btn(#nav_at, "SubBar", "id") %>
<% end %>
<% end %>
But, the yield in the nav_wrapper method only picks up the last statement of each block. So in this example, I get the Top Nav wrapper, Foo and Bar are skipped, I get the Sub Nav wrapper (being the last statement in the outer nav_wrapper block), SubFoo is skipped, and I get SubBar (being the last statement in the inner nav_wrapper block).
I know that the reason for this behavior is that the block of code is implicitly returning the last evaluated value, but I know there are lots of template helpers that render all the interstitial lines (form_for, for example). Can someone help me figure out what the magic trick is here?
When a ERB template is compiled, it is converted to code which adds strings to a buffer. (Look at the source code for ERB to see what I mean.) Methods from Action View like form_for execute the block, and then retrieve the text in the ERB buffer.
Open up the lib/ruby/1.9.1/gems/1.9.1 folder, and look for actionpack. Open up whatever version of Action Pack you have, and go to lib/action_view/helpers/capture_helper.rb. There is a method in there called capture, which is used by form_for to execute a block and retrieve the text generated by ERB.
If you are writing a Rails helper, then presumably capture will be available to your code. If not, try include ActionView::Helpers::CaptureHelper.
I'm having an issue using a custom helper method in my Rails (3.0) app to output the required html.
I have the following call in my partial view:
_label.html.erb
<% display_resource "Diamond", #resource.diamond %>
And in the resource_helper.rb file:
module ResourceHelper
def display_resource(display_name, value)
"<tr><td>#{display_name} </td><td>#{value.to_s}%</td></tr>" if value > 0
end
end
The intended output is:
<tr>
<td>Diamond</td>
<td>15%</td>
<tr>
*granted, without the formatting, and the 15 is arbitrary
If I use the <%= ... %> when performing the method call, it'll output the string correctly, but it won't be html (ie I'll see "<tr><td>Diamond </td><td>15%</td></tr>" as opposed to "Diamond 15%")
What am I doing incorrectly?
You need to mark the string returned as "raw" and then use <%= %>
module ResourceHelper
def display_resource(display_name, value)
raw("<tr><td>#{display_name} </td><td>#{value.to_s}%</td></tr>") if value > 0 # string wrapped in raw
end
end