I want to interpolate an attribute and its value in an html tag.
If I only interpolate the value like this:
<span b="<%= "1 2 3"%>">
It works, resulting in:
<span b="1 2 3">
If I try to interpolate the attribute as well like this:
<span <%= "b='1 2 3'" %> >
Instead of the same result as before I get:
<span b="'1" 2="" 3'="">
what's going on? Where's the documentation describing this behavior?
UPDATE:
The extra quotes in the las example where added apparently by the browser, not ERB, that got me confused. ERB render the string as <span b="1 2 3"> so the browser assumes this is meant <span b=""1" 2="" 3"=""> and then resolve the entities.
What going on here is HTML escaping. In Rails unless you use raw or String#html_safe the entities in the string will be escaped which helps prevent cross site scripting attacks.
So if you do:
<span <%= raw "b='1 2 3'" %> >
This will produce the intended output. But a better way altogether is to use the tag helpers instead if the HTML you are creating is highly dynamic. String interpolation tends to get really lengthy and is hard to read.
<%= tag.span(b: "1 2 3") %>
<% end %>
Whatever hash arguments you pass are added as attributes to the tag.
you need to deeply understand the difference between using ' and "
' single quote - will out without any interpretation
"" double quotes - will output only after interpretation
in order to get the output you need, you can code like
<span <%= 'b="1 2 3"' %> >
Related
I have a requirement where I need to make links clickable in text while keeping any other html tags as text (not html_safe). This means I cannot make the entire text html_safe as that will render the other html tags and I cannot sanitize the text and remove the other html tags. I've seen other websites handle this by making the html_safe links and other text on their own lines. It looks like the following when inspecting the html.
<span>
"This is an "
https://example.com/
"other <b>HTML</b>"
</span>
What would be the best way to do this in Rails 4?
When you call .html_safe on a string your actually getting an object that behaves like a string but is a ActiveSupport::SafeBuffer. When you append a string to a ActiveSupport::SafeBuffer its automatically escaped. Lets say you want to construct a span where the text is user input:
'<span>'.html_safe + text +'</span>'.html_safe
In this case we are safe against an XXS attack as the user originated text is automatically escaped:
irb(main):004:0> "<span>".html_safe + "<script>alert('You have been haxxored!')</script>" + "</span>".html_safe
=> "<span><script>alert('You have been haxxored')</script></span>"
That's what happens automatically when you output a variable in your views as the view is constructed as a ActiveSupport::SafeBuffer. Whenever you output a regular string it will be automatically escaped thus its secure by default.
Of course there is always going to be a huge number of programmers that just give proceed to give themselves a XSS vulnerability out of ignorance:
# WAAAH! Rails is escaping my tags! Bad rails!
'<span>'+ text +'</span>'.html_safe
Another way to approach the problem is to use the tag helpers, partials or Nokogiri instead of using string concatenation to construct HTML which in itself is tedious, borderline unreadible and error prone.
I was able to get this working using the following.
#module ApplicationHelper
def url_regexp
#url_regexp ||= %r{
(?:(?:https?|ftp|file):\/\/|www\.|ftp\.)
(?:\([-A-Z0-9+&##\/%=~_|$?!:,.]*\)|
[-A-Z0-9+&##\/%=~_|$?!:,.])*
(?:\([-A-Z0-9+&##\/%=~_|$?!:,.]*\)|
[A-Z0-9+&##\/%=~_|$])
}ix
end
#in the view
<%- "This is a test https://example.com".partition(url_regexp).each do |text| %>
<%- if text =~ url_regexp %>
<%= "<a href='#{text}' target='_blank'>#{text}</a>".html_safe %>
<%- else %>
<%= text %>
<% end %>
The question says it all. If I put HTML directly into the (JSON-formatted) translation file, like this:
"test_html" : "click <a href='http://stackoverflow.com/'>here</a>",
I get this in my HTML:
click <a href='http://stackoverflow.com/'>here</a>
I also tried combining this in my translation file:
"test_html_placeholder" : "click %shere%s",
With this in my HTML:
<%= __('test_html_placeholder', '', '') %>
But got similar results.
The only thing I can get to work is this clumsiness:
"test_html_pre" : "click ",
"test_html_link" : "here",
"test_html_post" : ".",
with this:
<%= __('test_html_pre') %><%= __('test_html_link') %><%= __('test_html_post') %>
But it's so cumbersome as to be almost not worth doing, and moreover the word order in some languages would force me to put some empty strings in my translation files, which i18n-node doesn't seem to like as it spits out the key (attribute) name when it
encounters an empty string.
I also tried using "\" as an escape character in front of the symbols, but I got an invalid JSON error when I lifted sails (restarted the server).
Any ideas, workarounds? I'm using sails.js, it wasn't my decision but I'm stuck with it and it comes with i18n-node. It's kind of late in the day on this project to consider using another library, but not completely out of the question.
beside of any upcoming discussion whether to include (html-)code in language files or not:
try to use
<%- __('click') %>
instead of
<%= __('click') %>
in ejs (the sails default template engine) a '<%=' will escape any html tags while '<%-' puts output as is without touching it. I am pretty sure you'll find unescaped html in your .json files. i18n doesn't do any transformation other than JSON.stringify() but almost all template engines do escape strings by default to prevent xssi.
For those using pug/jade, you can use
!{ __('key_for_your_text') }
Another option for pug is using
p!= __('key_for_your_text')
I have a RoR slim template with the following:
input(type="text" placeholder="I'm looking for…")
But sadly it outputs the HTML entity escape 'as-is' i.e. string literal. I'm using the rails gem 'slim' for template rendering the input field.
Desired output with the ellipsis character …
<input type="text" placeholder="I'm looking for…">
Actual output
<input type="text" placeholder="I'm looking for…">
I've tried adding a html_safe call to the end but to no avail e.g.
input(type="text" placeholder="I'm looking for…").html_safe
Thanks a bunch.
Self solved, simple solution, obvious answer - set of parenthesis needed:
input(type="text" placeholder=("I'm looking for…".html_safe))
According to Slim's website , Text is escaped by default. To prevent escape, prefix with double equals signs. So (un-intuitively),
input(type="text" placeholder=="I'm looking for…")
should work just as well.
For stand-alone unescapes, one could use
span.classname[onclick="document.getElementById('id01').style.display='none'"]
=="×"
Remember: make sure the escape character is surrounded by double quotes!
<%= text_field_tag nil, nil, placeholder: "I'm looking for…".html_safe %>
or give more info about your input helper
I have the inherited the following string (I can do nothing about the format):
<iframe \n class=\"some_class\"\n type=\"text/html\" \n src=\"/embed/iframe_content.html?id=tsqA5D7_z10\" \n width=\"960\" \n height=\"593\" \n marginwidth=\"0\" \n marginheight=\"0\" \n frameborder=\"0\">\n</iframe>
I am rendering it in an erb template like this:
<%= the_string %>
At the moment it renders as text like this:
<iframe class="some_class" type="text/html" src="/embed/iframe_content.html?id=tsqA5D7_z10" width="960" height="593" marginwidth="0" marginheight="0" frameborder="0"></iframe>
I need to render it as HTML.
I have tried the following:
<%= the_string.html_safe %> # Renders the string unchanged
<%= CGI.unescapeHTML(the_string) %> # Errors with a Type Error 'can't dup NilClass'
<%= CGI.unescapeHTML(the_string).html_safe %> # Errors with a Type Error 'can't dup NilClass'
<%= raw the_string %> # Renders the string unchanged
How can I render this string as HTML?
As you seem to have noticed, there are two things you need to take care of:
Unescaping the HTML entities
Printing the raw html in your view
For number 2 <%= raw ... %> should work fine.
For number 1 CGI.unescapeHTML was the right idea, but I don't think it recognizes all HTML entities so I would recommend taking a look at the HTML Entites gem
You can also try and use the simple_format helper method, but I think you are going to have to pass it some options for it to allow the <iframe> tag
also I would strongly suggest moving your unescaping logic into a helper method.
what you are unescaping must not be a string and thats why you are getting Errors with a Type Error can't dup NilClass
Try doing
s = String.new your_obj.to_s
Now do
CGI.unescapeHTML(s)
In the end I had to use the HTMLEntities Gem suggested by Matthew;
Installed the gem with RVM and added it to my Gemfile
Required it in my application.rb
The following was the only way I could get it to render correctly. Note the extra single quotes wrapped around the_string. Without them the angle brackets don't render, though everything else does.
coder = HTMLEntities.new
raw coder.decode("'"+the_string+"'")
You can try this:
<%= raw the_string %>
Version 3 sounds valuable. Any reason why you are not using the_string?
<%= raw CGI.unescapeHTML(the_string) %>
I got a rails app where I can input a few paragraphs of text into my model. The problem is I dont know how to input any line breaks.
I've tried to add " {ln}{/ln} ; { } and {br}{/br}" but that only displays the html as text and no break.
Is there anyway I can set it so the text area control will use any of the html I place within the model entry?
Is there any thing I can type so rails will recognize, hey put a line here?
Line breaks in textareas are produced as `\n'. However, the problem is that if you simply dump it into your view, it will just be line breaks in your HTML source.
You can try using the Rails simple_format helper to take care of some of this for you: http://api.rubyonrails.org/classes/ActionView/Helpers/TextHelper.html#M002285
It will auto-convert line breaks to HTML tags. You can use it with something like <%= simple_format(my_text_field) %>.
The problem isn't so much editing the value as it is rendering it later. To add newline characters to your value while editing it in a textarea, just hit the return key. When you re-edit that value later, the whitespace should still be there.
Rendering the whitespace is the tricky part. In HTML, whitespace is generally insignificant. A renderer like the one your browser uses will display a single space for any continuous string of whitespace. So merely dumping the value onto the page won't be enough:
<%= obj.description %>
Even though your value may be "One \t \n \n Two", it will show up on the screen as "One Two".
To get those new line characters to actually separate the lines when displayed, you'll need to convert them to HTML before rendering:
<%= obj.description.gsub(/\n/, '<br/>') %>
Of course, if users are entering data that will be included in your HTML, you should be escaping the values to protect against XSS. If new lines are the only thing you need to support, it should be as simple as this:
<%= h(obj.description).gsub(/\n/, '<br/>') %>
If you want to allow more complex formatting, look into Markdown and Textile (both of which Rails provides helper view methods for). Just be sure to investigate what if any support they provide for XSS prevention.
Keep user input unmodified and add this to your css:
white-space: pre-line;
It will display \r or \n (enter) in user input as a new line.
Here is another way to display the line breaks in a string while still escaping the rest of the text:
<%= safe_join(#object.textarea_input.split("\r\n"), "<br />".html_safe) %>
See here http://code.byteblues.com/2012/03/23/preloading-a-text-input-area-text_area-with-data-that-contains-a-line-break/
<%=raw text_area_tag :keywords, keywords, :rows => 8 %>
the problem with simple_format is that it's also adding other tags like <b><i><hr><h1>...
if you just want line breaks without other tags i suggest you build a partial (lets call it line_break):
<% text.split("\n").each do |t| %>
<%= t %><br>
<% end %>
then, just call it from your view:
<%= render partial: 'line_break', locals: {text: some_text} %>
What version of rails are you using?? Because the way to handle this, is different in rails 2 and 3.
Let's say the value of the record is "foo<br />bar"
In rails 3, if you want to evaluate the html, you could do <%=raw "foo<br />bar" %>, if you do so, you'll get a line break when you will see the view.
In rails 2 you don't have to do that, just do <%= "foo<br />bar" %>
Also, HTML doesn't get evaluated in a textarea anyway.
\n if memory serves (it hasn't been doing so well today... try at your own risk lol)
Edit: making the assumption you were talking about a textarea, if it is simple output, just use <br>
The answers above were good:
the gsub (#Ian) worked well
the simple_format (#Karl) was a bit over the top as #Aaron pointed out, wrapping everything in <p>
So I tweaked as follows:
simple_format(value, {}, wrapper_tag: 'div')
The other answers are wrong. Text area does not render as line breaks, because the innerHTML value of the TEXTAREA element does not render HTML..
You need to add the Line feed HTML entity:
EXAMPLE:
<textarea><%= "LINE 1
LINE 2
LINE 3".html_safe %></textarea>
See also New line in text area - Stack Overflow
If you are simply displaying your string in the view. then try it with
< p >This is my text< / p >< br />