Allow id attributes with simple_format helper - ruby-on-rails

As a proof of concept here's some console output first:
ruby-1.9.2-p180 :010 > x = "<span id='c_3'>s</span>"
=> "<span id='c_3'>s</span>"
ruby-1.9.2-p180 :011 > helper.simple_format(x)
=> "<p><span>s</span></p>"
The reason for this is that the Rails helper method simple_format call the sanitize method at the very end of it's execution and that method strips out attributes.
I know that sanitize will allow you to specify attributes that should not be stripped. My question is: Is it possible to somehow pass the "white listed" attribute (id in this case) THROUGH simple_format ?
thanks!!

simple_format(x,{}, :sanitize => false)

You cannot pass a white-list, but you can disable sanitization completely by doing
simple_format(x, :sanitize => false)
http://api.rubyonrails.org/classes/ActionView/Helpers/TextHelper.html#method-i-simple_format

Related

Ruby - link_to - How to add data directly from DB

First of all, I am very new to ruby and I am trying to maintain an application already running in production.
I have been so far able to "interpret" the code well, but there is one thing I am stuck at.
I have a haml.html file where I am trying to display links from DB.
Imagine a DB structure like below
link_name - Home
URL - /home.html
class - clear
id - homeId
I display a link on the page as below
< a href="/home.html" class="clear" id="home" > Home </a>
To do this I use 'link_to' where I am adding code as follows
-link_to model.link_name , model.url, {:class => model.class ...... }
Now I have a new requirement where we have a free text in DB, something like -
data-help="home-help" data-redirect="home-redirect" which needs to come into the options.
So code in haml needs to directly display content versus assign it to a variable to display.
In other words I am able to do
attr= '"data-help="home-help" data-redirect="home-redirect"' inside the <a>, but not able to do
data-help="home-help" data-redirect="home-redirect" in <a> tag.
Any help would be greatly appreciated!
link_to accepts a hash :data => { :foo => "bar" } of key/val pairs that it will build into data- attributes on the anchor tag. The above will create an attr as follows data-foo="bar"
So you could write a method on the model to grab self.data_fields (or whatever it's called) and split it into attr pairs and then create a hash from that. Then you can just pass the hash directly to the :data param in link_to by :data => model.custom_data_fields_hash
This somewhat verbose method splits things out and returns a hash that'd contain: {"help"=>"home-help", "redirect"=>"home-redirect"}
def custom_data_fields_hash
# this would be replaced by self.your_models_attr
data_fields = 'data-help="home-help" data-redirect="home-redirect"'
# split the full string by spaces into attr pairs
field_pairs = data_fields.split " "
results = {}
field_pairs.each do |field_pair|
# split the attr and value by the =
data_attr, data_value = field_pair.split "="
# remove the 'data-' substring because the link_to will add that in automatically for :data fields
data_attr.gsub! "data-", ""
# Strip the quotes, the helper will add those
data_value.gsub! '"', ""
# add the processed pair to the results
results[data_attr] = data_value
end
results
end
Running this in a Rails console gives:
2.1.2 :065 > helper.link_to "Some Link", "http://foo.com/", :data => custom_data_fields_hash
=> "<a data-help=\"home-help\" data-redirect=\"home-redirect\" href=\"http://foo.com/\">Some Link</a>"
Alternatively you could make it a helper and just pass in the model.data_attr instead
link_to "Some Link", "http://foo.com/", :data => custom_data_fields_hash(model.data_fields_attr)
Not sure you can directly embed an attribute string. You could try to decode the string in order to pass it to link_to:
- link_to model.link_name, model.url,
{
:class => model.class
}.merge(Hash[
str.scan(/([\w-]+)="([^"]*)"/)
])
)

Rails I18n, check if translation exists?

Working on a rails 3 app where I want to check if a translation exists before outputting it, and if it doesn't exist fall back to some static text. I could do something like:
if I18n.t("some_translation.key").to_s.index("translation missing")
But I feel like there should be a better way than that. What if rails in the future changes the "translation missing" to "translation not found". Or what if for some weird reason the text contains "translation missing". Any ideas?
Based on what you've described, this should work:
I18n.t("some_translation.key", :default => "fallback text")
See the documentation for details.
You can also use
I18n.exists?(key, locale)
I18n.exists?('do_i_exist', :en)
:default is not always a solution. Use this for more advanced cases:
helpers/application.rb:
def i18n_set? key
I18n.t key, :raise => true rescue false
end
any ERB template:
<% if i18n_set? "home.#{name}.quote" %>
<div class="quote">
<blockquote><%= t "home.#{name}.quote" %></blockquote>
<cite><%= t "home.#{name}.cite" %></cite>
</div>
<% end %>
What about this ?
I18n.t('some_translation.key', :default => '').empty?
I just think it feels better, more like there is no translation
Caveat: doesn't work if you intentionally have an empty string as translation value.
use :default param:
I18n.t("some_translation.key", :default => 'some text')
sometimes you want to do more things on translations fails
v = "doesnt_exist"
begin
puts I18n.t "langs.#{v}", raise: true
rescue
...
puts "Nooo #{v} has no Translation!"
end
This is a trick but I think it may be useful sometimes...
Assuming you have this in your i18n file:
en:
key:
special_value: "Special value"
default_value: "Default value"
You may do this:
if I18n.t('key').keys.include?(:special_value)
I18n.t('key.special_value')
else
I18n.t('key.default_value')
end
# => "Special value"
if I18n.t('key').keys.include?(:unknown_value)
I18n.t('key.special_value')
else
I18n.t('key.default_value')
end
# => "Default value"
NB: This only works if you're testing anything but a root key since you're looking at the parent.
In fact, what's interesting is what you can get when requesting a parent key...
I18n.t('key')
# => {:special_value=>"Special value", :default_value=>"Default value"}
Rails 4
I was iterating over some urls of jury members. The max amount of urls were 2, and default_lang was "de". Here is the yaml that I used
de:
jury:
urls:
url0: http://www.example.com
name0: example.com
url1:
name1:
en:
jury:
urls:
url0:
name0:
url1:
name1:
Here is how I checked if there was a url given and if it did not exist for another language, it would fallback to the I18n default_lang "de". I used answer of #albandiguer which worked great.
I Hope this helps someone:
<% 2.times do |j| %>
<% if I18n.exists?("jury.urls.url#{j}", "de") &&
I18n.exists?("jury.urls.name#{j}", "de") %>
<%= "<br/>".html_safe if j == 1%>
<a href="<%= t("jury.urls.url#{j}") %>" target="_blank">
<%= t("jury.urls.name#{j}") %>
</a>
<% end %>
<% end %>
Some versions ago there is a easier way i18next documentation > API > t:
You can specify either one key as a String or multiple keys as an Array of String. The first one that resolves will be returned.
Example:
i18next.t ( ['unknown.key', 'my.key' ] ); // It will return value for 'my.key'
Also you can use Contexts. t if not found a key into a context returns the default value.

Rails / Ruby - HTML attribute problem -

I have a tooltip that use this html attribute "original-title".
I have tryed this:
content_tag(:span, '', :class => options[:pinfo_class], :original-title => options[:pinfo])
But it gives a error in view.
Then I have used this which works, but not with the tooltip.
content_tag(:span, '', :class => options[:pinfo_class], :original_title => options[:pinfo])
How do I force rails to use the :original-title ?
You can use a string as a hash key, like 'original-title' => options[:pinfo]. Should work.
Also, most strings can be converted to symbols via 'some-string'.to_sym method, or even defined as :'some-string'.

link_to_unless problem

I have this RoR snippet in a view:
<%= link_to_unless(#posts_pages[:previous].nil?,
"Previous",
blog_with_page_path(:page_num => #posts_pages[:previous])) %>
Here blog_with_page is a named route. The snippet works if #posts_pages[:previous].nil? is false (as expected) and the link is generated correctly. However, when #posts_pages[:previous].nil? is true, instead of simply getting the "Previous" string back, I get an error telling me that the route couldn't be generated using :page_num=>nil. Is this the expected behavior? If the condition is met, the route code shouldn't be evaluated, should it?
Here's the complete error:
blog_with_page_url failed to generate from {:page_num=>nil, :action=>"show", :controller=>"pages"}, expected: {:action=>"show", :controller=>"pages"}, diff: {:page_num=>nil}
I've been looking at the link_to_unless code and I don't understand why I get the error since it should be returning simply the name:
# File actionpack/lib/action_view/helpers/url_helper.rb, line 394
def link_to_unless(condition, name, options = {}, html_options = {}, &block)
if condition
if block_given?
block.arity <= 1 ? capture(name, &block) : capture(name, options, html_options, &block)
else
name
end
else
link_to(name, options, html_options)
end
end
I'm using Rails 2.3.11 and Ruby 1.8.7
Cheers!
Because Ruby is not a lazy language, blog_with_page_path(:page_num => #posts_pages[:previous]) gets evaluated as soon as you call it, regardless of whether the value ever gets used by link_to_unless.
Given the various other answers which explain your problem, why not try this as your solution:
link_to( "Previous", blog_with_page_path(:page_num => #posts_pages[:previous]) ) unless #posts_pages[:previous].nil?
This will evaluate the "unless" condition first, sparing you the bogus link_to when #post_pages[:previous] is nil.
-- EDIT --
As pointed out in the comment, since you need the string back maybe the simplest way is just a ternary:
#posts_pages[:previous].nil? ? "Previous" : link_to( "Previous", blog_with_page_path(:page_num => #posts_pages[:previous]) )
It looks like a bug. This code is not "lazy" so it executes all statements. So you can go three ways:
Patch it
Make simple if .. else
Hack it:
Like this
<%= link_to_unless(#posts_pages[:previous].nil?,
"Previous",
blog_with_page_path(:page_num => #posts_pages[:previous] || 0)) %>
Instead of 0 you can set any number, it will never be setted
Function arguments are always evaluated before the function runs, whether or not they are needed:
ree-1.8.7-2011.03 :005 > def print_unless(condition, thing_to_print)
ree-1.8.7-2011.03 :006?> puts "I started executing"
ree-1.8.7-2011.03 :007?> puts thing_to_print unless condition
ree-1.8.7-2011.03 :008?> end
=> nil
ree-1.8.7-2011.03 :009 > print_unless(true, 1/0)
ZeroDivisionError: divided by 0
from (irb):9:in `/'
from (irb):9
from :0

Optional parameters for Rails Image Helper

In my current Rails (Rails 2.3.5, Ruby 1.8.7) app, if I would like to be able to define a helper like:
def product_image_tag(product, size=nil)
html = ''
pi = product.product_images.first.filename
pi = "products/#{pi}"
pa = product.product_images.first.alt_text
if pi.nil? || pi.empty?
html = image_tag("http://placehold.it/200x200", :size => "200x200")
else
html = image_tag(pi, size)
end
html
end
...and then call it from a view with either:
<%= product_image_tag(p) %>
...or:
<%= product_image_tag(p, :size => 20x20) %>
In other words, I'd like to be able to have this helper method take an optional size parameter. What would be the best way to go about this?
You're on the right track. I would do this:
def product_image_tag(product, options = {})
options[:size] ||= "200x200"
if img = product.product_images.first
image_tag("products/#{img.filename}", :alt => img.alt_text, :size => options[:size])
else
image_tag("http://placehold.it/#{options[:size]}", :size => options[:size])
end
end
Explanations:
Setting the final parameter to an empty hash is a common Ruby idiom, since you can call a method like product_image_tag(product, :a => '1', :b => '2', :c => '3', ...) without explicitly making the remaining arguments a hash with {}.
options[:size] ||= "200x200" sets the :size parameter to 200x200 if one wasn't passed to the method.
if img = product.product_images.first - Ruby lets you do assignment inside a condition, which is awesome. In this case, if product.product_images.first returns nil (no image), you fall back to your placehold.it link, otherwise display the first image.

Resources