How to replace Space with Line Break in Ruby on Rails? - ruby-on-rails

I am trying to replace Space in a string with Line Break in Ruby on Rails,
name = 'john smith'
i have tried the following so far:
name.gsub!(" ", "\n")
name.gsub!(" ", "<br>")
name.sub(" ", "\n")
name.sub(" ", "<br>")
but none of the above worked.

You have to be careful when marking a string as html_safe, especially if it may contain user input:
name = 'john smith<script>alert("gotcha")</script>'
name.gsub(' ', '<br>').html_safe
#=> "john<br>smith<script>alert(\"gotcha\")</script>"
Rails would output that string as-is, i.e. including the <script> tag.
In order to take advantage of Rails' HTML escaping, you should only mark the trusted parts as being html_safe. For a manually concatenated string:
''.html_safe + 'john' + '<br>'.html_safe + 'smith<script>alert("gotcha")</script>'
#=> "john<br>smith<script>alert("gotcha")</script>"
As you can see, only the <br> tag was left intact, the remaining parts were properly escaped.
There are several helpers for building safe strings as well as for building HTML tags. In your case, I'd use safe_join and tag:
name = 'john smith<script>alert("gotcha")</script>'
safe_join(name.split(' '), tag(:br))
#=> "john<br />smith<script>alert("gotcha")</script>"

While printing it in html you will need to use raw, otherwise rails will escape the tags
= raw name.gsub(" ", "<br>")

Try another one:
<%= name.gsub(" ", "<br>").html_safe %>
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)
#=> ""

Related

How to remove all the <br> from the first paragraph and last using regex

I am trying to get rid of all the extra <br> in the first paragraph and last paragraph.
For example:
st = "<p><br><br><br><br>apple</p>
<p>bananas</p>
<p>orange<br><br><br><br><br></p>
<p>tomatoes</p>
<p>berry<br><br><br><br><br><br></p>"
I'm hoping to end up with this:
"<p>apple</p>
<p>bananas</p>
<p>orange<br><br><br><br><br></p>
<p>tomatoes</p>
<p>berry</p>"
My goal is to leave the <br> middle paragraphs (ex. orange paragraph) alone and remove all the first paragraph <br> and all the end the last paragraph.
I've tried doing this regex:
st.sub(/^((<p>)|<br( \/)?>)*|(<p>|<br( \/)?>|< \/p>)*$/, '')
I get this:
=> "<p>apple</p>
<p>bananas</p>
<p>orange<br><br><br><br><br></p>
<p>tomatoes</p>
<p>berry<br><br><br><br><br><br></p>"
I am unable to delete the last paragraph repeating <br>.
Don't use regular expressions. Instead use a parser:
require 'nokogiri'
doc = Nokogiri::HTML::DocumentFragment.parse(<<EOT)
<p><br><br><br><br>apple</p>
<p>bananas</p>
<p>orange<br><br><br><br><br></p>
<p>tomatoes</p>
<p>berry<br><br><br><br><br><br></p>
EOT
p_tags = doc.search('p')
[:first, :last].each { |s| p_tags.send(s).search('br').remove }
doc.to_html
Which would result in the fragment looking like:
# => "<p>apple</p>\n" +
# "<p>bananas</p>\n" +
# "<p>orange<br><br><br><br><br></p>\n" +
# "<p>tomatoes</p>\n" +
# "<p>berry</p>\n"
Parsers are much more able to cope with changing HTML so if you're going to do any HTML changes or scraping it pays off to learn how to use them.
An alternate way to do what you want without a parser or a complicated regex is:
str = <<EOT
<p><br><br><br><br>apple</p>
<p>bananas</p>
<p>orange<br><br><br><br><br></p>
<p>tomatoes</p>
<p>berry<br><br><br><br><br><br></p>
EOT
str_lines = str.lines
[0, -1].each { |i| str_lines[i].gsub!(/<br>/, '') }
puts str_lines.join
Which results in the same thing.
The strength of the first method is that it won't care if the <br> mysteriously change to <br/> as in HTML5, or <br >.
Finally, if you doubly insist on using a longer, more complicated, pattern, at least simplify it:
puts str.sub(/\A<p>(?:<br>)+/, '<p>').sub(/(?:<br>)+<\/p>\Z/, '</p>')
which results in the same thing again.
Regular expressions are great for some tasks, but they're not good for markup. If you insist on using a regular expression, then simplify the problem as in the later solutions because it reduces the complexity of the pattern, which improves readability and eases maintenance.
st = st.gsub(/(?<=\A<p>)(<br\/?>)+|(<br\/?>)+(?=[<]\/p>\Z)/, '')
There's 2 parts seperated by a pipe (OR):
1) (?<=\A<p>)(<br\/?>)+ matches 1 or more <br> that are after the start of the string (\A) and a <p> tag
2) (<br\/?>)+(?=[<]\/p>\Z) matches matches 1 or more <br> that are before a </p> closing tag at the end of the string (\Z)
And gsub because we want to replace all occurrences in the string, not just the first.
The g in gsub stands for global.
I suggest something simple that's easy to understand, test and maintain.
str =<<-_
<p><br><br><br><br>apple</p>
<p>bananas</p>
<p>orange<br><br><br><br><br></p>
<p>tomatoes</p>
<p>berry<br><br><br><br><br><br></p>
_
#=> "<p><br><br><br><br>apple</p>\n<p>bananas</p>\n<p>orange<br><br><br><br><br></p>\n<p>tomatoes</p>\n<p>berry<br><br><br><br><br><br></p>\n"
first, *mid, last = str.lines
first.gsub('<br>', '') << mid.join << last.gsub('<br>', '')
#=> "<p>apple</p>\n<p>bananas</p>\n<p>orange<br><br><br><br><br></p>\n<p>tomatoes</p>\n<p>berry</p>\n"
puts s
<p>apple</p>
<p>bananas</p>
<p>orange<br><br><br><br><br></p>
<p>tomatoes</p>
<p>berry</p>
Note that
first
#=> "<p><br><br><br><br>apple</p>\n"
mid
#=> ["<p>bananas</p>\n",
# "<p>orange<br><br><br><br><br></p>\n",
# "<p>tomatoes</p>\n"]
last
#=> "<p>berry<br><br><br><br><br><br></p>\n"

Rails 4 - manipulate form input and display in view

I have a page where I take input from a form and then display it in a view.
View:
<%= form_tag("/page", method:"get") do %>
<%= text_area_tag(:x, #input)%>
<%= submit_tag("Submit Form") %> <%end%>
<%=#input%>
Controller:
def myMethod
if params[:x].present?
#input = "#{params[:x]}"
end
This works fine however I want to be able to identify where there are spaces in the string and then replace the spaces with a new line, and add a ",". For example, if the user inputs ‘cat dog mouse’ i want the view to return:
'cat',
'dog',
'mouse',
Is there an easy way to do this with a ruby function or will I need to write a regular expressions text search?
Thanks
A simple gsub will do:
"cat dog mouse".gsub(" ", ",\n")
This will replace every occurrence of a space with a comma/newline ,.
Update
Since you want to encapsulate each line with single quotes, a simple way to do it would be:
"cat dog mouse".split # Split the string into an array (automatically splits by space)
.map{|w| "'#{w}'"}} # Reassemble it with single quotes added
.join(",\n") # Convert the array into a string again and insert the comma/newline characters between each entry
That code, of course, can all be written on one line.
Here's another quick way to do this:
string = "cat dog mouse"
new_string = "'" + string.split.join("',\n'") + "'" # Outputs the same as above. Less friendly to read, but is also shorter.
You can use split, map and join:
"cat dog mouse".split(" ").map {|a| "'#{a}',\n"}.join
split creates a list ["cat", "dog", "mouse"]
map transforms it ["'cat',\n", "'dog',\n", "'mouse',\n"]
join creates a string again "'cat',\n'dog',\n'mouse',\n"

how to render Ruby array as JavaScript array in ERB template [duplicate]

This question already has an answer here:
Use ruby array for a javascript array in erb. Escaping quotes
(1 answer)
Closed 7 years ago.
I need to render a Ruby array in a very specific format for an erb template. This is because I am using JQcloud to build word clouds using JQuery, and is apparently picky about array formatting.
Here is the way that JQcloud requires a JS array to be formatted:
var word_array = [
{text: "Lorem", weight: 15},
{text: "Ipsum", weight: 9},
{text: "Dolor", weight: 6},
{text: "Sit", weight: 7},
{text: "Amet", weight: 5}
// ...as many words as you want
];
So what I have created in my controller are two arrays, one array of words to build my cloud, and another array of weights for each word.
ruby_word_array = ["Lorem","Ipsum","Dolor","Sit","Amet"]
ruby_weight_array = [15,10,13,8,4]
I need to convert my two Ruby arrays in such a way that they render properly with erb. So far I have come up with:
var wordArray = <%= raw #word_array.map{|a, i| {text: #word_array[0], weight: 15} } %> # I just hard coded the weight for simplicity
This gives me something that's close, but not close enough, and it ends up formatted like so:
var wordArray = [{:text=>"Lorem", :weight=>15}, {:text=>"Ipsum", :weight=>15}]
I really just need to know how to modify my last example to render in the Python style hash syntax {key: "value"},{key_2: "value_2"}
This is honestly a tricky one and I am stumped. The library I am using for this is called JQcloud, and it has a Ruby gem which I have incorporated into this Rails app. Here is a link.
Why don't your just use to_json?
# in ruby
#array = [{:text=>"Lorem", :weight=>15}, {:text=>"Ipsum", :weight=>15}]
Then, in the view:
var wordArray = <%= #array.to_json.html_safe %>;
Which will render:
var wordArray = [{"text":"Lorem","weight":15},{"text":"Ipsum","weight":15}];
You should create a helper function in app/helpers that does the behaviour you want. It's better to leave complex logic out of the view. Then in the view
var wordArray = <%= myHelper #word_array %>
And in the helper
def myHelper(word_array):
string = "["
word_array.each do |word|
string << "{text: \"#{word[:text]}\", weight: #{word[:weight]}},"
string = string.chomp(",") #in case JS hates the last comma
string << "]"
return string
Really, though, you can put anything you want in myHelper. You could pass both arrays and put them together in the helper. You could add newlines to the strings. Anything is possible
In such 2 Arrays situation, zip is useful.
ruby_word_array.zip(ruby_weight_array).map{|word, weight| "{text: #{word}, weight: #{weight}}"}.join(',')
If you need [],
'[' + ruby_word_array.zip(ruby_weight_array).map{|word, weight| "{text: #{word}, weight: #{weight}}"}.join(',') + ']'

Truncate & Simple Format String in Ruby on Rails

I am trying to take a string and render it with simple_format while at the same time truncating it. It works when I just use one or the other, but not when I do both. Why is this not doing simple_format and truncating simultaneously.
Controller
myString = "Apple’s New Laptop"
View
<%= simple_format truncate( myString, :length => 20 ) %>
The way to do this is to truncate after you have used simple_format on the string. Since truncate escapes the string by default, you have to use the escape: false option.
> myString = "Apple’s New Laptop"
> truncate(simple_format(myString), escape: false)
> => "<p>Apple’s New Laptop..."
> truncate(simple_format(myString), escape: false, length: 19)
> => "<p>Apple’s..."
This has the potential to create unbalanced HTML tags by cutting the </p> for example, so use carefully.
There was something changed in the truncate-helper in Rails 4.
The documentation does tells us:
The result is marked as HTML-safe, but it is escaped by default, unless :escape is false.
http://apidock.com/rails/v4.0.2/ActionView/Helpers/TextHelper/truncate
Rails normally escapes all strings. If you just want to put some unicode chars in strings in your code, you can do it by using the \u notation with the hexadecimal code. Then truncate will also count the char as exactly one char.
myString = "Apple\u2019s New Laptop"
This might be late but useful to someone else. This worked for me.
<%= truncate(myString, escape: false, length: 20 ) %>

Rails escape_javascript creates invalid JSON by escaping single quotes

The escape_javascript method in ActionView escapes the apostrophe ' as backslash apostrophe \', which gives errors when parsing as JSON.
For example, the message "I'm here" is valid JSON when printed as:
{"message": "I'm here"}
But, <%= escape_javascript("I'm here") %> outputs "I\'m here", resulting in invalid JSON:
{"message": "I\'m here"}
Is there a patch to fix this, or an alternate way to escape strings when printing to JSON?
Just call .to_json on a string and it will be escaped properly e.g.
"foo'bar".to_json
I ended up adding a new escape_json method to my application_helper.rb, based on the escape_javascript method found in ActionView::Helpers::JavaScriptHelper:
JSON_ESCAPE_MAP = {
'\\' => '\\\\',
'</' => '<\/',
"\r\n" => '\n',
"\n" => '\n',
"\r" => '\n',
'"' => '\\"' }
def escape_json(json)
json.gsub(/(\\|<\/|\r\n|[\n\r"])/) { JSON_ESCAPE_MAP[$1] }
end
Anyone know of a better workaround than this?
May need more details here, but JSON strings must use double quotes. Single quotes are okay in JavaScript strings, but not in JSON.
I had some issues similar to this, where I needed to put Javascript commands at the bottom of a Rails template, which put strings into jQuery.data for later retrieval and use.
Whenever I had a single-quote in the string I'd get a JavaScript error on loading the page.
Here is what I did:
-content_for :extra_javascript do
:javascript
$('#parent_#{parent.id}').data("jsonized_children", "#{escape_javascript(parent.jsonized_children)}");
Already there is an issue in github/rails
https://github.com/rails/rails/issues/8844
Fix to mark the string as html_safe
<%= escape_javascript("I'm here".html_safe) %>
or even better you can sanitize the string
<%= sanitize(escape_javascript("I'm here")) %>
<%= escape_javascript(sanitize("I'm here")) %>

Resources