Rails - Building a helper that breaks long words/URLs with <WBR> - ruby-on-rails

my app sends out emails. If there is a very long word or a long URL, it is breaking the email viewing experience by not letting the iphone zoom ad tighten in.
Here's what I've come up with so far but it's not working, thoughts?
Helper
def html_format(string, max_width=12)
text = string.gsub("\n", '<br />').html_safe.strip
(text.length < max_width) ?
text :
text.scan(/.{1,#{max_width}}/).join("<wbr>")
return text
end
View
<%= html_format(#comment.content) %>

Here's a method I found online that seems to work well for splitting long strings with <wbr>:
def split_str(str, len = 10)
fragment = /.{#{len}}/
str.split(/(\s+)/).map! { |word|
(/\s/ === word) ? word : word.gsub(fragment, '\0<wbr />')
}.join
end

This post shows how to wrap long words with regular expressions.

Related

RoR. Styling a helper method in rails

I am trying to style a helper method. The method works fine but html_safe (or how I have done it here) does not work to style it. I tried other variations as well like putting html_safe after .to_s, didn't work either.
Here is my latest approach.
def tweeted_text(counted)
if current_user.tweets.count == 1
first = "<b>current_user.tweets.count.to_s</b>" + " Tweet"
first.html_safe
else
second = "<b>current_user.tweets.count.to_s</b>" + " Tweets"
second.html_safe
end
end
In my view
<%= tweeted_text(#counted) %>
What would be an appropriate way to go about styling my helper?
ty
Please try this.
def tweeted_text
result = "<b>#{current_user.tweets.count}</b> Tweet"
result = result + "s" if current_user.tweets.count > 1
result.html_safe
end

Getting a double line break with a concat content_tag [duplicate]

My helper works like this:
def some_help(in_string)
in_string + " and more"
end
But I want it do to a before the output and I keep getting the < br > characters themselves literally, i.e. not a break but what I want is a < br > that is the problem.
so
def some_help(in_string)
"<br/>" + in_string + " and more"
end
doesn't work right.
Use tag(:br) instead of "<br/>".
content_tag(:br) creates opening and closing br tags and using raw or html_safe is just ugly (not to mention dangerous).
you can also use the "content_tag" view helper.
http://api.rubyonrails.org/classes/ActionView/Helpers/TagHelper.html#method-i-content_tag
def some_help
content_tag(:br) + "some help"
end
I'm not sure I understand you. You add <br /> in your string, and it stays in plain while you want it to have the effect of a newline ? If it is that, you have to mark your string as html-safe. you do this with "somestring".html_safe.
Rails automatically escapes HTML characters. Use .html_safe on the string.

Rails 3 - raw/html_safe not working in some cases?

I'm having difficulties with my output not being encoded even though I'm using raw or html_safe.
This one is writing out the &nbsp in my final HTML page.
def build_tag_cloud(tag_cloud, style_list)
tag_cloud.sort!{ |x,y| x.permalink <=> y.permalink }
max, min = 0, 0
tag_cloud.each do |tag|
max = tag.followers.to_i if tag.followers.to_i > max
min = tag.followers.to_i if tag.followers.to_i < min
end
divisor = ((max - min) / style_list.size) + 1
html = ""
tag_cloud.each do |tag|
name = raw(tag.name.gsub('&','&').gsub(' ',' '))
link = raw(link_to "#{name}", {:controller => "/shows", :action => "show", :permalink => tag.permalink}, :class => "#{style_list[(tag.followers.to_i - min) / divisor]}")
html += raw("<li>#{link}</li> ")
end
return raw(html.to_s)
end
What is allowed in using raw and html_safe? And how can my example above be fixed?
What class is this code from? The raw method is declared on a helper, so it can only be used on controllers and views.
Source: raw vs. html_safe vs. h to unescape html
Also, unless this method is on a view page (which would just be poor implementation of Rails' MVC), you can't use the link_to function. That helper is only available on views. Also, you shouldn't need to call raw repeatedly in this function. I would think that you could just do this:
def build_tag_cloud(tag_cloud, style_list)
...
html = ""
tag_cloud.each do |tag|
name = tag.name.gsub('&','&').gsub(' ',' ')
html += "<a href='#{shows_show_path(tag.permalink)}' class='#{style_list[(tag.followers.to_i - min) / divisor]}'>#{name}</a>"
end
html.html_safe
end
The raw and html_safe methods both specifically tell rails not to escape your output (raw is preferred, and obviates the explicit to_s).
raw Reference
html_safe Reference
I suspect the reason you are using raw is because of the li tags. I would recommend using a content tag helper for those. Then you shouldn't need to mess around with encoding at all. You may need to put the link_to method directly into the content_for :li for the link to work properly (I would try without first).
content_tag Reference

Don't escape html in ruby on rails

rails 3 seems to escape everything, including html. I have tried using raw() but it still escapes html. Is there a workaround? This is my helper that I am using (/helpers/application_helper.rb):
module ApplicationHelper
def good_time(status = true)
res = ""
if status == true
res << "Status is true, with a long message attached..."
else
res << "Status is false, with another long message"
end
end
end
I am calling the helper in my view using this code:
<%= raw(good_time(true)) %>
You can use .html_safe like this:
def good_time(status = true)
if status
"Status is true, with a long message attached...".html_safe
else
"Status is false, with another long message".html_safe
end
end
<%= good_time(true) %>
I ran into this same thing and discovered a safer solution than using html_safe, especially once you introduce strings which are dynamic.
First, the updated code:
def good_time(long_message1, long_message2, status = true)
html = "".html_safe
html << "Status is #{status}, "
if status
html << long_message1
else
html << long_message2
end
html
end
<%= good_time(true) %>
This escapes long_message content if it is unsafe, but leaves it unescaped if it is safe.
This allows "long message for success & such." to display properly, but also escapes "malicious message <script>alert('foo')</script>".
The explanation boils down to this -- 'foo'.html_safe returns an ActiveSupport::SafeBuffer which acts like a String in every way except one: When you append a String to a SafeBuffer (by calling + or <<), that other String is HTML-escaped before it is appended to the SafeBuffer. When you append another SafeBuffer to a SafeBuffer, no escaping will occur. Rails is rendering all of your views under the hood using SafeBuffers, so the updated method above ends up providing Rails with a SafeBuffer that we've controlled to perform escaping on the long_message "as-needed" rather than "always".
Now, the credit for this answer goes entirely to Henning Koch, and is explained in far more detail at Everything you know about html_safe is wrong -- my recap above attempts only to provide the essence of the explanation in the event that this link ever dies.

rails: get a teaser/excerpt for an article

I have a page that will list news articles. To cut down on the page's length, I only want to display a teaser (the first 200 words / 600 letters of the article) and then display a "more..." link, that, when clicked, will expand the rest of the article in a jQuery/Javascript way. Now, I've all that figured out and even found the following helper method on some paste page, which will make sure, that the news article (string) is not chopped up right in the middle of a word:
def shorten (string, count = 30)
if string.length >= count
shortened = string[0, count]
splitted = shortened.split(/\s/)
words = splitted.length
splitted[0, words-1].join(" ") + ' ...'
else
string
end
end
The problem that I have is that the news article bodies that I get from the DB are formatted HTML. So if I'm unlucky, the above helper will chop up my article string right in the middle of an html tag and insert the "more..." string there (e.g. between ""), which will corrupt my html on the page.
Is there any way around this or is there a plugin out there that I can use to generate excerpts/teasers from an HTML string?
You can use a combination of Sanitize and Truncate.
truncate("And they found that many people were sleeping better.",
:omission => "... (continued)", :length => 15)
# => And they found... (continued)
I'm doing a similar task where I have blog posts and I just want to show a quick excerpt. So in my view I simply do:
sanitize(truncate(blog_post.body, length: 150))
That strips out the HTML tags, gives me the first 150 characters and is handled in the view so it's MVC friendly.
Good luck!
My answer here should do work. The original question (err, asked by me) was about truncating markdown, but I ended up converting the markdown to HTML then truncating that, so it should work.
Of course if your site gets much traffic, you should cache the excerpt (perhaps when the post is created/updated, you could store the excerpt in the database?), this would also mean you could allow the user to modify or enter their own excerpt
Usage:
>> puts "<p><b>Something</p>".truncate_html(5, at_end = "...")
=> <p><b>Someth...</b></p>
..and the code (copied from the other answer):
require 'rexml/parsers/pullparser'
class String
def truncate_html(len = 30, at_end = nil)
p = REXML::Parsers::PullParser.new(self)
tags = []
new_len = len
results = ''
while p.has_next? && new_len > 0
p_e = p.pull
case p_e.event_type
when :start_element
tags.push p_e[0]
results << "<#{tags.last}#{attrs_to_s(p_e[1])}>"
when :end_element
results << "</#{tags.pop}>"
when :text
results << p_e[0][0..new_len]
new_len -= p_e[0].length
else
results << "<!-- #{p_e.inspect} -->"
end
end
if at_end
results << "..."
end
tags.reverse.each do |tag|
results << "</#{tag}>"
end
results
end
private
def attrs_to_s(attrs)
if attrs.empty?
''
else
' ' + attrs.to_a.map { |attr| %{#{attr[0]}="#{attr[1]}"} }.join(' ')
end
end
end
Thanks a lot for your answers!
However, in the meantime I stumbled upon the jQuery HTML Truncator plugin, which perfectly fits my purposes and shifts the truncation to the client-side. It doesn't get any easier :-)
you would have to write a more complex parsers if you dont want to split in the middle of html elements. it would have to remember if it is in the middle of a <> block and if its between two tags.
even if you did that, you would still have problems. if some put the whole article into an html element, since the parser couldnt split it anywhere, because of the missing closing tag.
if it is possible at all i would try not to put any tags into the articles or keep it to tags that dont contain anything (no <div> and so on). that way you would only have to check if you are in the middle of a tag which is pretty simple:
def shorten (string, count = 30)
if string.length >= count
shortened = string[0, count]
splitted = shortened.split(/\s/)
words = splitted.length
if(splitted[words-1].include? "<")
splitted[0,words-2].join(" ") + ' ...'
else
splitted[0, words-1].join(" ") + ' ...'
else
string
end
end
I would have sanitized the HTML and extracted the first sentence. Assuming you have an article model, with a 'body' attribute that contains the HTML:
# lib/core_ext/string.rb
class String
def first_sentence
self[/(\A[^.|!|?]+)/, 1]
end
end
# app/models/article.rb
def teaser
HTML::FullSanitizer.new.sanitize(body).first_sentence
end
This would convert "<b>This</b> is an <em>important</em> article! And here is the rest of the article." into "This is an important article".
I solved this using following solution
Install gem 'sanitize'
gem install sanitize
and used following code, here body is text containing html tags.
<%= content_tag :div, Sanitize.clean(truncate(body, length: 200, separator: ' ', omission: "... #{ link_to '(continue)', '#' }"), Sanitize::Config::BASIC).html_safe %>
Gives excerpt with valid html.
I hope it helps somebody.
There is now a gem named HTMLTruncator that takes care of this for you. I've used it to display post excerpts and the like, and it's very robust.
If you are using Active Text, I would suggest first converting the text using to_plain_text.
truncate(sanitize(career.content.body.to_plain_text), length: 150).squish

Resources