Truncate + Sanitize in Rails Views - ruby-on-rails

I ran into a small problem today when I was trying to use sanitize and truncate in conjunction with one another to create an excerpt for my blog. Each of the methods worked by itself, but used together it would only truncate. I tried both of these syntaxes (the former being recommended in a blog post titled "Six Ruby on Rails Tips & Tricks"):
<%= truncate(sanitize(post.content), length: 580) %>
<%= sanitize(truncate(post.content, length: 580, separator: '<p>')) %>
And then I tried to put truncate in the controller, and sanitized that object in the view, but still no.
Finally I got it to work like this:
<%= sanitize(post.content.truncate(580, separator: '</p>')) %>
What I'd like to know is why didn't it work when I wrapped a method in another method? What's the difference with the last way I tried it?
TIA
'bondibox'

This worked for me:
<%= sanitize(article.description[0..100]) %>

Truncate and Sanitize are not included in controllers, they are part of ActionView::Helpers::TextHelper and ActionView::Helpers::SanitizeHelper respectively. These modules are not included per default in a controller, so you cannot use it in there.
However, both are included in the views (templates) and you can therefore use them in there. You can include the modules stated above in a controller class to use them there, but i would not recommend it.
The reason the second statement works is because Rails extends some base objects from Ruby, like String with several methods. so you actually call sanitize on a truncated version of a string truncated by a method of String.
The combination of both is a bit tricky. I cannot really tell you why the combination of the module version of sanitize and truncate does not work without a little more info. What exactly did you try to accomplish here (examples?)

An old question, but landed on it while struggling with this myself. The problem is that sanitize will not strip all HTML tags, but just a few that are defined by default, such as script. So you have to specifiy that no tags are allowed:
truncate sanitize(post.content, tags: [], attributes: []), length: 580

Thanks Ruben,
<%= sanitize(article.description[0..100]) %>
is working perfectly in Rails 6.
Our experience is that all other combinations w/ truncate aren't working.

Related

Different text i18n in Rails

In my rails application I have a partial(file1/_partial.html.erb) that must be rendered in Two form file2/form1.html.erb and file3/_partial.html.erb, I'am wondering what is the best solution to i18n a text in the partial
actually what I'm doing is
<%= (t :to_ranslate, :scope => 'file2.form1' ) %>
file2:
form1:
to_ranslate: "translated"
and this is working but I'm wondering if there is a solution where can I have different translation based on template so for the same partial i will have different text based on where it is rendered
If you do not need different translations when included in different templates you can just use the "Lazy Lookup" as described here in 4.1.4: http://guides.rubyonrails.org/i18n.html#looking-up-translations
It also applies to rendering partials, for example:
in file1/_partial.html.erb
<%= (t '.to_translate') %>
in the translations.yml:
en:
file1:
_partial:
to_translate: "translated"
For using different translations depending on where you render from, like so (untested but the principle should work):
in file1/_partial.html.erb
<%= (t "#{translation_scope.to_s}.to_translate') %>
in file2/form1.html.erb
<%= render '/file1/partial', translation_scope: 'file2._partial' %>
in file3/_partial.html.erb
<%= render '/file1/partial', translation_scope: 'file3._partial' %>
in the translations.yml
en:
file1:
_partial:
to_translate: "translated"
file2:
_partial:
to_translate: "translated"
file2:
_partial:
to_translate: "translated"
This would have the advantage that it still works when you do not specify the translation_scope (falling back to its default) and also when you pass it.
This is the reason why i would prefer it over using the scope: 'xx' like you did.
And the whole interface seems a little bit like inheritance in the views with the same structure everywhere.
In a more abstract and complicated way it would also be possible to use fallbacks for this, but in the example here this would be overkill. On larger projects it might make sense to implement something like this.
as far as i know rails is internationalized by default out of the box
just place the text as you would normally and it should work no problem.
reference: http://guides.rubyonrails.org/i18n.html

HTML "class" and "id" attributes using hyphens instead of undescores in Rails 4

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).

Rails prevent HAML from escaping a link (w/ helper haml_tag)

I'm trying to create a simple menu and I came across this problem: HAML keeps escaping my links to html entities. I have a helper that is supposed to generate a menu:
def buildMainMenu(file=Rails.root.join("config","menu.yaml"))
... some operations ...
link = url_for par.merge({:controller=>mitem["controller"], :action=>mitem["action"]})
... some more operations yay ...
haml_tag :a, mitem["label"], :href=>link
end
par is {"testPARAM1"=>"testVAL1","testPARAM2"=>"testVAL2"}
Sadly the output is
<a href='/test/test1?testPARAM1=testVAL1&testPARAM2=testVAL2'>Test2</a>
I've looked for a while now and I can't seem to find how to force HAML to NOT escape my strings :(
I know this isn't 100% what you are looking for, but personally I would refactor this - this is going to cause you headaches and anyway, rendering html within a helper isn't ideal at all.
I'd change the helper function to get your YAML file, or whatever is going on there, and output a final array with the correct items.
Make a _header.html.haml partial (put it in a directory 'shared'), the partial will call the helper function, get the array, and since you are in a view you can loop with normal techniques, and use link_to, etc, and all your problems are solved.
This is a much cleaner way of doing things.
Just figured it out (I wish I've found it before spending over an hour on it but hey).
For anyone interested:
There are two functions html_safe and raw that do the trick. Used as follow:
haml_tag :a, mitem["label"], :href=>link.html_safe
haml_tag :a, mitem["label"], :href=>raw(link)

Rails way to offer modified attributes

The case is simple: I have markdown in my database, and want it parsed on output(*).
#post.body is mapped to the posts.body column in the database. Simple, default Activerecord ORM. That column stores the markdown text a user inserts.
Now, I see four ways to offer the markdown rendered version to my views:
First, in app/models/post.rb:
# ...
def body
markdown = RDiscount.new(body)
markdown.to_html
end
Allowing me to simply call #post.body and get an already rendered version. I do see lots of potential problems with that, e.g. on edit the textfield being pre-filled with the rendered HMTL instead of the markdown code.
Second option would be a new attribute in the form of a method
In app/models/post.rb:
# ...
def body_mardownified
markdown = RDiscount.new(body)
markdown.to_html
end
Seems cleanest to me.
Or, third in a helper in app/helpers/application_helper.rb
def markdownify(string)
markdown = RDiscount.new(string)
markdown.to_html
end
Which is used in the view, instead of <%= body %>, <%= mardownify(body) %>.
The fourth way, would be to parse this in the PostsController.
def index
#posts = Post.find(:all)
#posts.each do |p|
p.body = RDiscount.new(string).to_html
#rendered_posts << p
end
end
I am not too familiar with Rails 3 proper method and attribute architecture. How should I go with this? Is there a fifth option? Should I be aware of gotchas, pitfalls or performance issues with one or another of these options?
(*) In future, potentially updated with a database caching layer, or even special columns for rendered versions. But that is beyond the point, merely pointing out, so to avoid discussion on filter-on-output versus filter-on-input :).
The first option you've described won't work as-is. It will cause an infinite loop because when you call RDiscount.new(body) it will use the body method you've just defined to pass into RDiscount (which in turn will call itself again, and again, and so on). If you want to do it this way, you'd need to use RDiscount.new(read_attribute('body')) instead.
Apart from this fact, I think the first option would be confusing for someone new looking at your app as it would not be instantly clear when they see in your view #post.body that this is in fact a modified version of the body.
Personally, I'd go for the second or third options. If you're going to provide it from the model, having a method which describes what it's doing to the body will make it very obvious to anyone else what is going on. If the html version of body will only ever be used in views or mailers (which would be logical), I'd argue that it makes more sense to have the logic in a helper as it seems like the more logical place to have a method that outputs html.
Do not put it in the controller as in your fourth idea, it's really not the right place for it.
Yet another way would be extending the String class with a to_markdown method. This has the benefit of working on any string anywhere in your application
class String
def to_markdown
RDiscount.new(self)
end
end
#post.body.to_markdown
normal bold italic
If you were using HAML, for example in app/views/posts/show.html.haml
:markdown
= #post.body
http://haml-lang.com/docs/yardoc/file.HAML_REFERENCE.html#markdown-filter
How about a reader for body that accepts a parse_with parameter?
def body(parse_with=nil)
b = read_attribute('body')
case parse_with
when :markdown then RDiscount.new(b)
when :escape then CGI.escape(b)
else b
end
end
This way, a regular call to body will function as it used to, and you can pass a parameter to specify what to render with:
#post.body
normal **bold** *italic*
#post.body(:markdown)
normal bold italic

Difference between t(:str) and t :str in ROR

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.

Resources