Suppose I have the following string
#x = "<a href='#'>Turn me into a link</a>"
In my view, I want a link to be displayed. That is, I don't want everything in #x to be unescaped and displayed as a string. What's the difference between using
<%= raw #x %>
<%= h #x %>
<%= #x.html_safe %>
?
Considering Rails 3:
html_safe actually "sets the string" as HTML Safe (it's a little more complicated than that, but it's basically it). This way, you can return HTML Safe strings from helpers or models at will.
h can only be used from within a controller or view, since it's from a helper. It will force the output to be escaped. It's not really deprecated, but you most likely won't use it anymore: the only usage is to "revert" an html_safe declaration, pretty unusual.
Prepending your expression with raw is actually equivalent to calling to_s chained with html_safe on it, but is declared on a helper, just like h, so it can only be used on controllers and views.
"SafeBuffers and Rails 3.0" is a nice explanation on how the SafeBuffers (the class that does the html_safe magic) work.
I think it bears repeating: html_safe does not HTML-escape your string. In fact, it will prevent your string from being escaped.
<%= "<script>alert('Hello!')</script>" %>
will put:
<script>alert('Hello!')</script>
into your HTML source (yay, so safe!), while:
<%= "<script>alert('Hello!')</script>".html_safe %>
will pop up the alert dialog (are you sure that's what you want?). So you probably don't want to call html_safe on any user-entered strings.
The difference is between Rails’ html_safe() and raw(). There is an excellent post by Yehuda Katz on this, and it really boils down to this:
def raw(stringish)
stringish.to_s.html_safe
end
Yes, raw() is a wrapper around html_safe() that forces the input to String and then calls html_safe() on it. It’s also the case that raw() is a helper in a module whereas html_safe() is a method on the String class which makes a new ActiveSupport::SafeBuffer instance — that has a #dirty flag in it.
Refer to "Rails’ html_safe vs. raw".
html_safe :
Marks a string as trusted safe. It will be inserted into HTML with no additional escaping performed.
"<a>Hello</a>".html_safe
#=> "<a>Hello</a>"
nil.html_safe
#=> NoMethodError: undefined method `html_safe' for nil:NilClass
raw :
raw is just a wrapper around html_safe. Use raw if there are chances that the string will be nil.
raw("<a>Hello</a>")
#=> "<a>Hello</a>"
raw(nil)
#=> ""
h alias for html_escape :
A utility method for escaping HTML tag characters. Use this method to escape any unsafe content.
In Rails 3 and above it is used by default so you don't need to use this method explicitly
The best safe way is: <%= sanitize #x %>
It will avoid XSS!
In Simple Rails terms:
h remove html tags into number characters so that rendering won't break your html
html_safe sets a boolean in string so that the string is considered as html save
raw It converts to html_safe to string
Short and Simple
Let's assume we can't trust user input.
Bad:
user_input.html_safe # asking for trouble
Good:
user_input.html_escape # or
h(user_input) # in some view
Inputs we control:
trusted_input_only.html_safe
that should be fine. but be careful what your trusted inputs are. They must only be generated from your app.
Related
Rails fills the id and class of an element generated with various input tag helpers (text_field for example) by itself. For example, in a form_for(#athlete), adding a text_field :height generates
<input name="athlete_height" ... />
I am a strong advocate of the use of hyphens in HTML ids and classes (and in CSS selectors consequently) (by reading MDN, because I like to write using the conventions dictated by the language - like in data-stuff - and because it's just better looking).
I read here and there that in Rails you can't fix this. This would be quite disappointing.
Do you know a way around this problem?
I'm afraid, underscores are hardcoded. From https://github.com/rails/rails/blob/master/actionview/lib/action_view/helpers/form_helper.rb, lines 446-450:
options[:html].reverse_merge!(
class: as ? "#{action}_#{as}" : dom_class(object, action),
id: (as ? [namespace, action, as] : [namespace, dom_id(object, action)]).compact.join("_").presence,
method: method
)
you can always provide your own id and class, or patch code of ActionView, which may be hard, tedious and error-prone
Recently ran into this very same situation and #lobanovadik has a good solution: just write your own helper method.
# app/helpers/dom_helper.rb
module DomHelper
dom_id_helper(model)
dom_id(model).dasherize
end
end
# view.html.erb
<%= link_to "Text", path, id: dom_id_helper(#model) %>
#=> Text
This has the benefit of not monkey-patching Rails or messing with any default methods/configuration. Thus, you won't "break" any updates to Rails.
It also gives you greater flexibility because you can now use both dashes or underscores depending on the situation. For instance, let's say there's a gem that expects IDs to have underscores...you won't break it.
As a personal preference, I always append _helper to all my own helper methods, so that I know it's a helper method and that it came from me and not from Rails (easier to debug).
I want to check a string and change any #something to link. So I have a helper function which consists of something like this:
def parse(content)
content.gsub(/#[a-zA-z0-9]+\b/, link_to("#{$1}", user_path($1)) )
end
But the result is
The problem is :
The is a string, because somehow the < and > is escaped.
Why does "#{$1}" return nothing? Isn't it supposed to return whatever is checked upon, in this case #something?
Rails HTML-escapes any content produced by a user-defined helper, unless you tell it not to. Try using <%= raw parse(content) %> in your view.
Quoting Pickaxe on gsub:
If a string is used as the replacement, special variables from the match (such as $& and $1)
cannot be substituted into it, because substitution into the string occurs before the pattern match
starts. However, the sequences \1, \2, and so on, may be used to interpolate successive numbered
groups in the match, and \k<name> will substitute the corresponding named captures.
So you can't use #{$1} because $1 isn't set until after the command has finished. Your best bet is probably to use the block form of gsub - in which case $1 is set inside the block. Try:
def parse(content)
content.gsub(/#[a-zA-z0-9]+\b/) {link_to($1, user_path($1))}
end
hey guys
when I store this string:
http://61.147.96.19/f4v/41/53283141.h264_2.f4v?10000&key=d7d7488b5dd4a35aac3e784cf4acb1a174ddc7&playtype=1&tk=2038443745&brt=3&id=tudou&itemid=30165756&fi=53283141&sz=19354294
in a variable #longurl
and use it in a erb file
<%= #longurl %>
It doesn't work, when I check the source file in the browser :
http://61.147.96.19/f4v/41/53283141.h264_2.f4v?10000&key=d7d7488b5dd4a35aac3e784cf4acb1a174ddc7&playtype=1&tk=2038443745&brt=3&id=tudou&itemid=30165756&fi=53283141&sz=19354294
and compare the differece, it add a amp; after each &, and I don't know how to avoid this.
BTW it seems #url is taken by the rails by default use, I can't save anything in the variable, Could anyone tell me why?
Thanks
Assuming you're using Rails 3, try <%= #longurl.html_safe %>.
You can use CGI::unescape to decode a URL-encoded string.
<%= CGI::unescape(#longurl) %>
For HTML entities, use CGI::unescapeHTML:
<%= CGI::unescapeHTML(#longurl) %>
You actually want &
Read why here: http://htmlhelp.com/tools/validator/problems.html
Is it 'breaking' the method in any other way, or just because it looks different?
If #url is used by Rails, use a different variable. It shouldn't be a deal breaker.
Before Rails 3, you used to have to code like this to make sure everything is HTML encoded:
<%= h #longurl %>
The h method would HTML encode your string. Now, everything is HTML encoded by default. If you don't want Rails to do this for you, we now have the raw method like this:
<%= raw #longurl %>
Read more about the raw method here:
http://api.rubyonrails.org/classes/ActionView/Helpers/RawOutputHelper.html#method-i-raw
or read about this change in the Rails 3 release notes
http://edgeguides.rubyonrails.org/3_0_release_notes.html#other-changes
I'm writing a webapp in Ruby on Rails 3. Rails 3 automatically escapes any potentially-bad strings, which is generally a good thing, but means if you assemble HTML yourself, you have to call html_safe on it.
I have a Card model, which has several text fields, the contents of which are not trusted (may contain evil HTML or script). I have a function which performs a few transforms on one of these text fields, using other knowledge about the specific Card, to produce HTML output. I want to embed the HTML produced by this function in several places throughout several parts of my app.
Conceptually, this helper is to do with the View. However, I can't find any way to write functions in my View files; it seems they have to go in Helpers or the Controller/Model.
Since this function is very much specific to a Card object, the next best option would be to have a function inside my Card model card.rb:
class Card < ActiveRecord::Base
[...]
def format(unsafe_text)
initial_text = h unsafe_text # aka html_escape unsafe_text
# assembles HTML output based on initial_text and fields of self
output_text.html_safe!
end
Then I'd like to call this in assorted views by doing things like:
Rules text: <%= format(#card.rulestext) %>
However, there's a big problem here as well. In the Card model card.rb, I am able to use the html_safe! function, but I'm not able to use h or html_escape. It seems that the h and html_escape functions are only available in ERB views, not in the helpers or controllers!
There are a few workarounds. I can make format not sanitize its input, and go
Rules text: <%= format(h(#card.rulestext)) %>
But that's both prone to dangerous slipups (one missing h() and we've got problems) and is very non-DRY. At the moment I'm using a partial to gain access to the h() function:
(in a normal view)
Rules text: <%= render 'formattext', :text=> #card.rulestext %>
(app/views/shared/_formattext.html.erb)
<%= #card.format(html_escape(text)) %>
But this still feels dangerous. All I have to do is make single forgetful call to format(sometext) in a view, rather than calling render 'formattext', :text=> sometext, and I've got unescaped text running around.
Is there any better way to do this? Is there a way to write helper functions to live in the View rather than the Model or the Controller?
Place the logic that does your view assembly into a CardHelper:
app/helpers/card_helper.rb
class CardHelper
def rules(card)
initial_text = h card.rules_text
# assembles HTML output based on initial_text and fields of card
output_text.html_safe
end
end
It's not clear from your example whether you want to format several fields via the format method. If that's the case, then you might be able to do:
class CardHelper
def format(card, attribute)
initial_text = h card[attribute]
# assembles HTML output based on initial_text and fields of card
output_text.html_safe
end
end
You can use this helper like any other:
class CardsController
helper CardHelper
end
and in your views:
<%= rules(#card) %>
or
<%= format(#card, :rules) %>
Escaping the content for view is a View responsibility, this is the reason why the h helper is not available in controllers or models.
Still, I don't understand why can't you simply sanitize the content in the view.
Also note that, in Rails 3, you don't need to call the h helper.
Content is sanitized automatically by default unless you flag it as html_safe!.
The main reason why is not logically true to use the h helper in the model is because the model should work view-independently. In other words, the model should not care whether the content is going to be embedded in a HTML document or JSON file (which requires a different escaping approach compared to HTML).
i am new to ROR.. i am having a doubt in internationalization commands.
in some case we were using <%=t :str_use%>
and in some cases we were using <%= t(:str_use) %>
what is the difference between these two
when should i have to use 1st and when to use the second one..
Pls give some ideas regarding this.
i am having a view file with in that i am having lot of strings i wanna to internationalization them.
in some cases i am having like <td>Use</td>
and in some cases
<% if use %> Use <br />
<% else %>
This is ruby's syntax, not specifically ror ;)
Both are the same. Ruby can guess the parenthesis even if they're not there.
So it's completely up to you.
There's no difference between t :str and t(:str) — they both call the method t with the symbol :str as an argument. In Ruby, parentheses around arguments are optional.
But these are both different from t: str, which is Ruby 1.9 shorthand for the hash {:t => str}.
When to use t(:str)? When you want to chain further methods.
Try this in Rails:
t 'some.translation'.capitalize
t('some.translation').capitalize
First approach will return:
Translation
..as in the second half the identifier after the period, instead of translating the whole text. This, from what I can tell, is because you are passing the argument 'some.translation'.capitalize, not calling capitalize on the return, like the second example.