Line break in string returned by a helper method - ruby-on-rails

I have a helper method that returns a string after formatting it, which includes adding line breaks.
I am calling this helper method in a view and am trying to display this formatted string.
I am using "\n" or "\r\n" to introduce line breaks, but this shows up as mere spaces in the browser.

You should use <br> or create it like tag('br'):
your_string = "test string" + tag('br')
your_string.html_safe #return your string
As #max rightly pointed, from a security vulnerability (XSS) aspect you can use h() on user-provided text, which converts your string to a safe string and allows you to securely call html_safe on the full string.

One mistake i made was using raw(string) in the helper method instead of using it in view and it still was shown as 'smth smth' so be aware of that.
My code looked something like this
td= helper_method()
And when I changed it to the following it worked:
td= raw(helper_method())

Related

Why does ActionView's "select_tag" escape the HTML in its "options" argument when called directly?

So I've been going through the very poor documentation that exists for ActionView, particularly a method called select_tag that just exists when called from view files. Supposedly, it's called like this:
select_tag name, option_tags, options
The documentation says nothing at all about the name, very little about the options, and describes the option_tags only through examples that treat it as an opaque value that must be obtained from other functions.
As always, the only way to learn anything about Rails is to reverse-engineer it.
So I tried running it directly from a Rails console, which is tricky because Ruby doesn't let you call methods that are defined in modules unless you create a class and an object first:
class H
include ActionView::Helpers::FormOptionsHelper
include ActionView::Helpers::FormTagHelper
end
H.new.options_for_select ["foo","bar"]
The above usage of options_for_select comes from actual code that somebody else wrote. The return value is a string:
"<option value=\"foo\">foo</option>\n<option value=\"bar\">bar</option>"
So apparently, you're supposed to pass the return value from option_for_select (or one of the many other related functions that introduce complications I don't want to talk about such as generating HTML tags from ActiveRecord objects) as the option_tag parameter of select_tag. Except if you copy that string to your clipboard and paste it directly into a function call, it doesn't do what you'd expect:
H.new.select_tag :my_name, "<option value=\"foo\">foo</option>\n<option value=\"bar\">bar</option>"
Return value:
"<select name=\"my_name\" id=\"my_name\"><option value="foo">foo</option>\n<option value="bar">bar</option></select>"
At least this reveals what the name parameter is for.
Even weirder, the text is not escaped if you pass the return value directly to select_tag without letting it print on the console:
H.new.select_tag :name, H.new.options_for_select(["foo","bar"])
Return value:
"<select name=\"name\" id=\"name\"><option value=\"foo\">foo</option>\n<option value=\"bar\">bar</option></select>"
WTF is going on here?
In the course of writing this question, I stumbled on its answer: Ruby has been lying to me (like it always does).
When you evaluate:
H.new.options_for_select ["foo","bar"]
Ruby tells you that the result was a String. But that's only because Pry and Irb both silently call .to_s on everything, and the thing that gets returned from options_for_select has a to_s. The truth:
(H.new.options_for_select ["foo","bar"]).class
=> ActiveSupport::SafeBuffer
ActiveSupport::SafeBuffer.new("<foo>")
=> "<foo>"
So whoever wrote these methods assumed that you want to incorporate raw, user-provided strings into your <select> tags, and those strings could contain attempts at HTML/JavaScript injection, so they must be escaped.
ActiveView treats all strings as suspect, but it is possible to mark certain strings as "safe" by wrapping them in an ActiveSupport::SafeBuffer.

grails i18n line break

Using the Grails internationalization messages.properties I'm trying to create a multi-line message, but cannot seem to find a way to create a new line without using the <br> element, and I'd prefer to keep presentation logic out of the message. I've tried using "\n" but that doesn't get rendered.
I know I can use multiple messages "message.1=...", "message.2=...", but that doesn't seem as clean either.
Here's what I'd like to be able to do:
messages.properties
helptext=First Line\nSecond Line\nThird Line
page.gsp
<g.message code="helptext"/>
result:
First Line
Second Line
Third Line
Everything I've found either says to use <br> element, or do a replaceAll on \n, but I was hoping to not have to use extra processing to handle this.
I think you have to use <br> in the message directly.
//messages.properties
helptext=First Line<br>Second Line<br>Third Line
//Gsp
<p><g:message code="helptext"/><p>
\ gives the ability to break the line in the properties file but renders as a single line in view.
For me (i18n message properties in Grails 2.0 project) worked following line:
property = Line1\\nLine2\\nLine3
HTML tag BR worked also fine if displayed on HTML page, but was not any good for me, because I in my case this text needed to be a text string not HTML.
You could write a custom tag that converts \n into br tags as well. It would just need to call the messageSource bean and parse the results. Thus your messages would not have to be HTML-specific

How to output html_safe within <%=%> block while concatenating strings?

Consider this:
<%
str = "http://domain.com/?foo=1&bar=2"
%>
Now these cases:
<%=str%>
# output:http://domain.com/?foo=1&bar=2
<%=str.html_safe%>
# output:http://domain.com/?foo=1&bar=2
<%="#{str.html_safe}"%>
# output:http://domain.com/?foo=1&bar=2
<%=""+str.html_safe%>
# output:http://domain.com/?foo=1&bar=2
I need to output the URL with other strings. How can I guarantee that the ampersand will be unescaped? For reasons beyond my control I can't send &.
Please help! Pulling my hair here :\
EDIT: To clarify, I actually have an array like so:
#images = [{:id=>"fooid",:url=>"http://domain.com/?foo=1&bar=2"},...]
I am creating a JS array (the image_array var) to use in my app this way:
image_array.push(<%=#images.map{|x|"{id:'#{x[:id]}',url:'#{x[:url].html_safe}'}"}.join(",")%>);
This generates:
image_array.push({id:'fooid',url:'http://domain.com/?foo=1&bar=2'},...);
Which does not work in my specific case. I need the url without the amp; part.
When you write:
"#{foo.bar}"
this is ~equivalent to writing
foo.bar.to_s
So what you are actually doing is:
<%=str.html_safe.to_s%>
…which Rails no longer sees as being safe, and so it hits your resulting string with a round of HTML escaping.
I don't know the internals of Rails, but I assume that the html_safe method extends the string object with an instance variable flagging it as OK, but when you wrap that in another string via interpolation you are getting a new string without that flag.
Edit: To answer your needs, use raw or call html_safe on your final string:
<%=raw "foo#{str}"%>
<%="foo#{str}".html_safe%>
or in your case:
image_array.push(<%=raw #images.map{…}.join(',')%>);
image_array.push(<%=#images.map{…}.join(',').html_safe%>);
See also this question.
Use this
<%=str.html_safe.to_s%>
or
<%=raw(str)%>
give you better results
image_array.push(<%= #images.map{|x| "{id:'#{x[:id]}',url:'#{x[:url]}'}".html_safe }.join(",") %>);
what you would do to be safe is:
image_array.push(<%= #images.map { |image| image.as_json(only: [:id, :url]) }.to_json } %>)
this will escape the <, >, etc. properly like this:
[{"name":"\u003ch1\u003eAAAA\u003c/h1\u003e"}]
and for people coming here like me who want to concatenate strings, it's just not safe to do it, the best way is to concatenate tags, e.g.
content_tag(:p) do
content_tag(:span, "<script>alert(1)</script>") +
link_to("show", user)
end
will work fine and properly escape the first string

Can't get regex captured group working in Ruby on Rails method

I need to parse and replace text using gsub and a regular expression. A simplified example appears below where I'm saving one of the captured groups -- \3 -- for use in my replacement string.
my_map.gsub(/(\shref=)(\")(\d+), ' href="/created_path/' + '\3' + '" ' + ' title="' + AnotherObject.find('\3')'"')
In the first use of the captured value, I'm simply displaying it to build the new path. In the second example, I am calling a find with the captured value. The second example will not work.
I've tried various ways of escaping the value ("\3", ''\3'', etc) and even built a method to test displaying the value (works) or using the value in a method (doesn't work).
Any advice is appreciated.
Use the block form of gsub and replace your \3 references with $3 globals:
my_map.gsub(/(\shref=)(\")(\d+)/) { %Q{ href="/created_path/#{$3}" title="#{AnotherObject.find($3)"} }
I also switched to %Q{} for quoting to avoid the confusing quote mixing and concatenation.
The second argument in the replacement-string form of gsub (i.e. the version of gsub that you're trying to use) will be evaluated and concatenated before gsub is called and **before **the \3 value is available so it won't work.
As an aside, is there a method you should be calling on what AnotherObject.find($3) returns?

Help interpreting this bit of Rails code

What is this?
"#{h params[:chat_input]}"
I am referring to the hash # and the h.
Most likely this is inside a double-quoted string, such as "Ponies all love #{h params[:chat_input]}!" The #{stuff} expression causes the stuff expression to be interpreted and inserted into the string. For example "1 + 2 = #{1 + 2}" will result in the string "1 + 2 = 3".
The h is an alias to the html_escape method, which is pretty self-explanatory.
The code you paste, by itself, is just a comment. I assume the code is inside a string, though.
"hello, #{5 + 5}"
# => hello, 10
The statement inside the brackets will be evaluated as Ruby. This is called string interpolation.
The statement inside the interpolation in your code is a method that gets an argument.
h params[:chat_input]
h(params[:chat_input])
The h method is a shortcut for html_escape, which escapes HTML. For example, <span> is converted into <span>, so that the browser displays the actual contents of the string, instead of interpreting it as HTML.
html_escape(params[:chat_input])
You probably know what params is.
To sum up, you get a HTML escaped version of whatever params[:chat_input] contains.
"#{h params[:chat_input]}"
In ruby, double-quoted strings allow for expressions to be evaluated and automatically converted to strings.
I can do this:
years = 25
"John is " + years + " years old"
but I'll get an error because I can't add the number to a string.
I can do
"John is #{years} years old"
to get around that.
The h() method is a Rails helper function that removes HTML tags. It's a safety thing.
Finally, params() is a method in Rails that gives you access to GET and POST parameters. It's actually wrapping a hash GET and POST parameters are symbolized to reduce memory (symbols are only defined once, whereas a string like "foo" is a new object every time.)
So, params[:chat_input] retrieves the value from the previous request's GET or POST parameters, and in your case it looks like it's just displaying and sanitizing them.
Hope that helps!
It's just interpolating a value inside a string. The :chat_input is a symbol, it's used in place of a string because symbols are only created once.
h(something)
or
h something
since ruby does not force the use of (), is a function available in rails that converts the parameter to a "safe HTML" string avoiding interpreting the possible HTML code inside of the 'something' variable.
"#{x}"
in ruby means converting the x variable to a string and placing it in the new string for example:
"#{host}:#{port}"
will place the value of host and the value of port into the new string formed by the "", in a way that if host is "localhost" and port is 30 the result string will be "localhost:30"
params is a special rails hash that contains the post/get parameters passed to the controller method being executed
another detail is that in ruby a method always returns the last evaluated expression
so the method
def test
"#{h params[:chat_input]}"
end
will return a string that has the HTML-safe value of the post/get parameter chat_input
holy crap, is that from chat_sandbox by any chance?
if so, let me know if you need any help $)
I'm hoping to update that code here soon.

Resources