rails to_json remove quote - ruby-on-rails

I am working the the LogMeIn Central API and in the body of my request I need to send some Json. I have this:
host_ids = LmiHost.all.collect {|lmi| lmi.host_id}.join ', '
create_servicetag_report_request.body = {hostIds: host_ids, fields: 'ServiceTag'}.to_json
This turns the body into
{\"hostIds\":\"5888, 6225, 214752\",\"fields\":\"ServiceTag\"}
how can i remove the
\"
from this section:
\"5888, 6225, 214752\"
it is not suppose to have quotes around it.
I am using Ruby on Rails

The reason to_json adds the \" (escaped quotations) is because it is converting hostIds as a string. In your rails console try this to see the difference.
{"hostids":[0,1,2,3]}.to_json
=> "{\"hostids\":[0,1,2,3]}"
{"hostids":"[0,1,2,3]"}.to_json
=> "{\"hostids\":\"[0,1,2,3]\"}"
This can be seen another way by trying: puts [1,2,3,4] vs puts "[1,2,3,4]"
Ultimately I would refer to the LMI Central API to figure out exactly how multiple hostIds can be sent.

You can use JSON.parse(create_servicetag_report_request.body[:hostIds]) to parse it.

Just remove the join part from this line:
host_ids = LmiHost.all.collect { |lmi| lmi.host_id }.join ', '
join joins your array of ids into a comma separated string. This doesn't seems to be what you want.
Btw. you can shorten .collect { |lmi| lmi.host_id } to map(&:host_id):
create_servicetag_report_request.body = {
hostIds: LmiHost.all.map(&:host_id),
fields: 'ServiceTag'
}.to_json

Related

Tidy long string in Ruby

I have a method in Ruby, which needs an API URL:
request_url = "http://api.abc.com/v3/avail?rev=#{ENV['REV']}&key=#{ENV['KEY']}&locale=en_US&currencyCode=#{currency}&arrivalDate=#{check_in}&departureDate=#{check_out}&includeDetails=true&includeRoomImages=true&room1=#{total_guests}"
I want to format it to be more readable. It should take arguments.
request_url = "http://api.abc.com/v3/avail?
&rev=#{ENV['REV']}
&key=#{ENV['KEY']}
&locale=en_US
&currencyCode=#{currency}
&arrivalDate=#{check_in}
&departureDate=#{check_out}
&includeDetails=true
&includeRoomImages=true
&room1=#{total_guests}"
But of course there's line break. I tried heredoc, but I want it to be in one line.
I would prefer to not build URI queries by joining strings, because that might lead to URLs that are not correctly encoded (see a list of characters that need to be encoded in URIs).
There is the Hash#to_query method in Ruby on Rails that does exactly what you need and it ensure that the parameters are correctly URI encoded:
base_url = 'http://api.abc.com/v3/avail'
arguments = {
rev: ENV['REV'],
key: ENV['KEY'],
locale: 'en_US',
currencyCode: currency,
arrivalDate: check_in,
departureDate: check_out,
includeDetails: true,
includeRoomImages: true,
room1: total_guests
}
request_url = "#{base_url}?#{arguments.to_query}"
You could use an array and join the strings:
request_url = [
"http://api.abc.com/v3/avail?",
"&rev=#{ENV['REV']}",
"&key=#{ENV['KEY']}",
"&locale=en_US",
"&currencyCode=#{currency}",
"&arrivalDate=#{check_in}",
"&departureDate=#{check_out}",
"&includeDetails=true",
"&includeRoomImages=true",
"&room1=#{total_guests}",
].join('')
Even easier, you can use the %W array shorthand notation so you don't have to write out all the quotes and commas:
request_url = %W(
http://api.abc.com/v3/avail?
&rev=#{ENV['REV']}
&key=#{ENV['KEY']}
&locale=en_US
&currencyCode=#{currency}
&arrivalDate=#{check_in}
&departureDate=#{check_out}
&includeDetails=true
&includeRoomImages=true
&room1=#{total_guests}
).join('')
Edit: Of course, spickermann makes a very good point above on better ways to accomplish this specifically for URLs. However, if you're not constructing a URL and just working with strings, the above methods should work fine.
You can extend strings in Ruby using the line continuation operator. Example:
request_url = "http://api.abc.com/v3/avail?" \
"&rev=#{ENV['REV']}" \
"&key=#{ENV['KEY']}"

How to have gsub handle multiple patterns and replacements

A while ago I created a function in PHP to "twitterize" the text of tweets pulled via Twitter's API.
Here's what it looked like:
function twitterize($tweet){
$patterns = array ( "/((([A-Za-z]{3,9}:(?:\/\/)?)(?:[-;:&=\+\$,\w]+#)?[A-Za-z0-9.-]+|(?:www.|[-;:&=\+\$,\w]+#)[A-Za-z0-9.-]+)((?:\/[\+~%\/.\w-_]*)?\??(?:[-\+=&;%#.\w_]*)#?(?:[\w]*))?)/",
"/(?<=^|(?<=[^a-zA-Z0-9-\.]))#([A-Za-z_]+[A-Za-z0-9_]+)/",
"/(?<=^|(?<=[^a-zA-Z0-9-\.]))#([A-Za-z_]+[A-Za-z0-9_]+)/");
$replacements = array ("<a href='\\0' target='_blank'>\\0</a>", "<a href='http://twitter.com/\\1' target='_blank'>\\0</a>", "<a href='http://twitter.com/search?q=\\1&src=hash' target='_blank'>\\0</a>");
return preg_replace($patterns, $replacements, $tweet);
}
Now I'm a little stuck with Ruby's gsub, I tried:
def twitterize(text)
patterns = ["/((([A-Za-z]{3,9}:(?:\/\/)?)(?:[-;:&=\+\$,\w]+#)?[A-Za-z0-9.-]+|(?:www.|[-;:&=\+\$,\w]+#)[A-Za-z0-9.-]+)((?:\/[\+~%\/.\w-_]*)?\??(?:[-\+=&;%#.\w_]*)#?(?:[\w]*))?)/", "/(?<=^|(?<=[^a-zA-Z0-9-\.]))#([A-Za-z_]+[A-Za-z0-9_]+)/", "/(?<=^|(?<=[^a-zA-Z0-9-\.]))#([A-Za-z_]+[A-Za-z0-9_]+)/"]
replacements = ["<a href='\\0' target='_blank'>\\0</a>",
"<a href='http://twitter.com/\\1' target='_blank'>\\0</a>",
"<a href='http://twitter.com/search?q=\\1&src=hash' target='_blank'>\\0</a>"]
return text.gsub(patterns, replacements)
end
Which obviously didn't work and returned an error:
No implicit conversion of Array into String
And after looking at the Ruby documentation for gsub and exploring a few of the examples they were providing, I still couldn't find a solution to my problem: How can I have gsub handle multiple patterns and multiple replacements at once?
Well, as you can read from the docs, gsub does not handle multiple patterns and replacements at once. That's what causing your error, quite explicit otherwise (you can read that as "give me a String, not an Array!!1").
You can write that like this:
def twitterize(text)
patterns = [/((([A-Za-z]{3,9}:(?:\/\/)?)(?:[-;:&=\+\$,\w]+#)?[A-Za-z0-9.-]+|(?:www.|[-;:&=\+\$,\w]+#)[A-Za-z0-9.-]+)((?:\/[\+~%\/.\w-_]*)?\??(?:[-\+=&;%#.\w_]*)#?(?:[\w]*))?)/, /(?<=^|(?<=[^a-zA-Z0-9-\.]))#([A-Za-z_]+[A-Za-z0-9_]+)/, /(?<=^|(?<=[^a-zA-Z0-9-\.]))#([A-Za-z_]+[A-Za-z0-9_]+)/]
replacements = ["<a href='\\0' target='_blank'>\\0</a>",
"<a href='http://twitter.com/\\1' target='_blank'>\\0</a>",
"<a href='http://twitter.com/search?q=\\1&src=hash' target='_blank'>\\0</a>"]
patterns.each_with_index do |pattern, i|
text.gsub!(pattern, replacements[i])
end
text
end
This can be refactored into more elegant rubyish code, but I think it'll do the job.
The error was because you tried to use an array of replacements in the place of a string in the gsub function. Its syntax is:
text.gsub(matching_pattern,replacement_text)
You need to do something like this:
replaced_text = text.gsub(pattern1, replacement1)
replaced_text = replaced_text.gsub(pattern2, replacement2)
and so on, where the pattern 1 is one of your matching patterns and replacement is the replacement text you would like.

ruby regex with quotes

I'm trying to pass more than one regex parameter for parts of a string that needs to be replaced. Here's the string:
str = "stands in hall "Let's go get to first period everyone" Students continue moving to seats."
Here is the expected string:
str = "stands in hall "Let's go get to first period everyone" Students continue moving to seats."
This is what I tried:
str.gsub(/'|"/, "'" => "\'", """ => "\"")
This is what I got:
"stands in hall \"Let's go get to first period everyone\" Students continue moving to seats."
How do I get the quotes in while sending in two regex parameters using gsub?
This is an HTML unescaping problem.
require 'cgi'
CGI.unescape_html(str)
This gives you the correct answer.
From my comments on this question:
Your updated version is correct. The only reason the slashes are in your final line of code is that it's an escape sequence so that you don't mistakenly think the first slash is used to terminate the string. Try assigning your output and printing it:
str1 = str.gsub(/'|"/, "'" => "\'", """ => "\"")
puts str1
and you'll see that the slashes are gone when str1 is printed using puts.
The difference is that autoevaluating variables within irb (which is what I assume you're doing to execute this sample code) automatically calls the inspect method, which for string variables shows the string in its entirety.
Because I did not understand unescaping characters I found an alternative solution that might be the "rails-way"
Can you use <%= raw 'some_html' %>
My final solution ended up being this instead of messy regex and requiring CGI
<%= raw evidence_score.description %>
Unescaping HTML string in Rails

How do I scan url for a specific string with spaces and special characters?

I'm using stringscanner on my request URL in order to get the name of the user's currently selected category, but I've been having difficulty dealing with spaces and special characters.
request.url.scan(/\?category=\w+/).to_s.gsub('?category=', '')
URL examples followed by result
http://localhost:3000/search?category=dog&search=&utf8=%E2%9C%93 => ["dog"]
http://localhost:3000/search?category=dog.com&search=&utf8=%E2%9C%93 => ["dog"]
http://localhost:3000/search?category=dog+cat&search=&utf8=%E2%9C%93 => ["dog"]
I'm trying to get ["dog"] ["dog.com"] and ["dog cat"], but am currently stuck. Any ideas?
Note: Considering removing spaces from categories and replacing them with dashes as multiple spaces could be problematic, but if it's possible to create one function to rule them all, that would be awesome.
This is Rails, is there a reason you're not just using params[:category]?
If you are trying to extract params then you could use parse_query :
uri = "http://localhost:3000/search?category=dog+cat&search=&utf8=%E2%9C%93"
result = Rack::Utils.parse_query(URI(uri).query) #=> {"category"=>"dog cat", "search"=>"", "utf8"=>"\xE2\x9C\x93"}
result["category"] #=> dog cat

Ruby gsub function

I'm trying to create a BBcode [code] tag for my rails forum, and I have a problem with the expression:
param_string.gsub!( /\[code\](.*?)\[\/code\]/im, '<pre>\1</pre>' )
How do I get what the regex match returns (the text inbetween the [code][/code] tags), and escape all the html and some other characters in it?
I've tried this:
param_string.gsub!( /\[code\](.*?)\[\/code\]/im, '<pre>' + my_escape_function('\1') + '</pre>' )
but it didn't work. It just passes "\1" as a string to the function.
You should take care of the greedy behavior of the regular expressions. So the correct code looks like this:
html.gsub!(/\[(\S*?)\](.*?)\[\/\1\]/) { |m| escape_method($1, $2) }
The escape_method then looks like this:
def escape_method( type, string )
case type.downcase
when 'code'
"<pre>#{string}</pre>"
when 'bold'
"<b>#{string}</b>"
else
string
end
end
Someone here posted an answer, but they've deleted it.
I've tried their suggestion, and made it work with a small change. Whoever you are, thanks! :)
Here it is
param_string.gsub!( /\[code\](.*?)\[\/code\]/im ) {|s| '<pre>' + my_escape_function(s) + '</pre>' }
You can simply use "<pre>#{$1}</pre>" for your replacement value.

Resources