Consider the following query parameters
{
:param1=>"<script>alert('hi')</script>",
:param2=>"<script>alert('hi2')</script>"
}
I want to safely render these as query parameters in a link. The problem is demonstrated as follows:
[83] pry(main)> params
=> {:param1=>"<script>alert('hi')</script>", :param2=>"<script>alert('hi2')</script>"}
[84] pry(main)> params.to_query
=> "param1=%3Cscript%3Ealert%28%27hi%27%29%3C%2Fscript%3E¶m2=%3Cscript%3Ealert%28%27hi2%27%29%3C%2Fscript%3E"
[85] pry(main)> ERB::Util.html_escape params.to_query
=> "param1=%3Cscript%3Ealert%28%27hi%27%29%3C%2Fscript%3E¶m2=%3Cscript%3Ealert%28%27hi2%27%29%3C%2Fscript%3E"
When params.to_query is rendered via ERB, the ampersand is escaped as well. You can probably pass these to url_for and link_to as query parameters, but for the purposes of this question, let's assume that's not possible.
In my case, I simply want to have the query parameters themselves safely escaped, but not have the ampersand escaped.
I came up with a potential solution, but I am curious about feedback from the community:
def escape_query_params(url)
# in my case, we have a string that can be parsed as a URI.
uri = URI.parse(url)
# then we split the query part across the "&".
# and return an array that uses the technique in the below article
# to concat strings starting with a SafeBuffer
# and then use ActionView's `safe_join` to bring back the &
safe_query_params = safe_join(uri.query.split("&").map{|s| "".html_safe + s}, "&".html_safe)
"".html_safe + uri.path + "?" + safe_query_params
end
The above uses a technique from the following article on how to be safe with html_safe: https://product.reverb.com/stay-safe-while-using-html-safe-in-rails-9e368836fac1
I'm doing some custom logging in my Rails application and I want to automatically sensor some parameters. I know that we have fitler_parameter_logging.rb which does this for the params object. How can I achieve something like this for my custom hash.
Let's say I'm logging something like this:
Rails.logger.info {name: 'me', secret: '1231234'}.inspect
So my secret key should be sensored in the logs.
I know I can personally delete the key before logging, but it adds noise to my application.
The question title talks about removing the parameters, but your question refers to censoring the parameters similar to how Rails.application.config.filter_parameters works. If it's the latter, it looks like that's already been answered in Manually filter parameters in Rails. If it's the former, assuming a filter list, and a hash:
FILTER_LIST = [:password, :secret]
hash = {'password' => 123, :secret => 321, :ok => "this isn't going anywhere"}
then you could do this:
hash.reject { |k,v| FILTER_LIST.include?(k.to_sym) }
That'll cope with both string and symbol key matching, assuming the filter list is always symbols. Additionally, you could always use the same list as config.filter_parameters if they are going to be the same and you don't need a separate filter list:
hash.reject { |k,v| Rails.application.config.filter_parameters.include?(k.to_sym) }
And if you wanted to make this easier to use within your own logging, you could consider monkey patching the Hash class:
class Hash
def filter_like_parameters
self.reject { |k,v| Rails.application.config.filter_parameters.include?(k.to_sym) }
end
end
Then your logging code would become:
Rails.logger.info {name: 'me', secret: '1231234'}.filter_like_parameters.inspect
If you do monkey patch custom functionality to core classes like that though for calls you're going to be making a lot, it's always best to use a quite obtuse method name to reduce the likelihood of a clash with any other library that might share the same method names.
Hope that helps!
I want to perform an action if a string is contained, non-case-sensitively, in another string.
So my if statement would look something like this:
#a = "search"
if #a ILIKE "fullSearch"
#do stuff
end
You can use the include? method. So in this case:
#var = 'Search'
if var.include? 'ear'
#action
end
Remember include? method is case-sensitive. So if you use something like include? 'sea' it would return false. You may want to do a downcase before calling include?()
#var = 'Search'
if var.downcase.include? 'sea'
#action
end
Hope that helped.
There are many ways to get there. Here are three:
'Foo'.downcase.include?('f') # => true
'Foo'.downcase['f'] # => "f"
Those are documented in the String documentation which you need to become very familiar with if you're going to program in Ruby.
'Foo'[/f/i] # => "F"
This is a mix of String's [] slice shortcut and regular expressions. I'd recommend one of the first two because they're faster, but for thoroughness I added it because people like hitting things with the regex hammer. Regexp contains documentation for /f/i.
You'll notice that they return different things. Ruby considers anything other than false or nil as true, AKA "truthiness", so all three are returning a true value, and, as a result you could use them in conditional tests.
You can use a regexp with i option. i for insensitive I think.
a = "fullSearch"
a =~ /search/i
=> 4
a =~ /search/
=> nil
Or you could downcase your string and check if it's present in the other
a = "fullSearch"
a.downcase.include?('search')
=> true
Rails' URL generation mechanism (most of which routes through polymorphic_url at some point) allows for the passing of a hash that gets serialized into a query string at least for GET requests. What's the best way to get that sort of functionality, but on top of any base path?
For instance, I'd like to have something like the following:
generate_url('http://www.google.com/', :q => 'hello world')
# => 'http://www.google.com/?q=hello+world'
I could certainly write my own that strictly suits my application's requirements, but if there existed some canonical library to take care of it, I'd rather use that :).
Yes, in Ruby's standard library you'll find a whole module of classes for working with URI's. There's one for HTTP. You can call #build with some arguments, much like you showed.
http://www.ruby-doc.org/stdlib/libdoc/uri/rdoc/classes/URI/HTTP.html#M009497
For the query string itself, just use Rails' Hash addition #to_query. i.e.
uri = URI::HTTP.build(:host => "www.google.com", :query => { :q => "test" }.to_query)
Late to the party, but let me highly recommend the Addressable gem. In addition to its other useful features, it supports writing and parsing uri's via RFC 6570 URI templates. To adapt the given example, try:
gsearch = Addressable::Template.new('http://google.com/{?query*}')
gsearch.expand(query: {:q => 'hello world'}).to_s
# => "http://www.google.com/?q=hello%20world"
or
gsearch = Addressable::Template.new('http://www.google.com/{?q}')
gsearch.expand(:q => 'hello world').to_s
# => "http://www.google.com/?q=hello%20world"
With vanilla Ruby, use URI.encode_www_form:
require 'uri'
query = URI.encode_www_form({ :q => "test" })
url = URI::HTTP.build(:host => "www.google.com", query: query).to_s
#=> "http://www.google.com?q=test"
I would suggest my iri gem, which makes it easy to build a URL through a fluent interface:
require 'iri'
url = Iri.new('http://google.com/')
.append('find').append('me') # -> http://google.com/find/me
.add(q: 'books about OOP', limit: 50) # -> ?q=books+about+OOP&limit=50
.del(:q) # remove this query parameter
.del('limit') # remove this one too
.over(q: 'books about tennis', limit: 10) # replace these params
.scheme('https') # replace 'http' with 'https'
.host('localhost') # replace the host name
.port('443') # replace the port
.path('/new/path') # replace the path of the URI, leaving the query untouched
.cut('/q') # replace everything after the host and port
.to_s # convert it to a string
This question already has answers here:
Parsing a JSON string in Ruby
(8 answers)
Closed 4 years ago.
I'm looking for a simple way to parse JSON, extract a value and write it into a database in Rails.
Specifically what I'm looking for, is a way to extract shortUrl from the JSON returned from the bit.ly API:
{
"errorCode": 0,
"errorMessage": "",
"results":
{
"http://www.foo.com":
{
"hash": "e5TEd",
"shortKeywordUrl": "",
"shortUrl": "http://bit.ly/1a0p8G",
"userHash": "1a0p8G"
}
},
"statusCode": "OK"
}
And then take that shortUrl and write it into an ActiveRecord object associated with the long URL.
This is one of those things that I can think through entirely in concept and when I sit down to execute I realize I've got a lot to learn.
These answers are a bit dated. Therefore I give you:
hash = JSON.parse string
Rails should automagically load the json module for you, so you don't need to add require 'json'.
Parsing JSON in Rails is quite straightforward:
parsed_json = ActiveSupport::JSON.decode(your_json_string)
Let's suppose, the object you want to associate the shortUrl with is a Site object, which has two attributes - short_url and long_url. Than, to get the shortUrl and associate it with the appropriate Site object, you can do something like:
parsed_json["results"].each do |longUrl, convertedUrl|
site = Site.find_by_long_url(longUrl)
site.short_url = convertedUrl["shortUrl"]
site.save
end
This answer is quite old. pguardiario's got it.
One site to check out is JSON implementation for Ruby. This site offers a gem you can install for a much faster C extension variant.
With the benchmarks given their documentation page they claim that it is 21.500x faster than ActiveSupport::JSON.decode
The code would be the same as Milan Novota's answer with this gem, but the parsing would just be:
parsed_json = JSON(your_json_string)
Here is an update for 2013.
Ruby
Ruby 1.9 has a default JSON gem with C extensions. You can use it with
require 'json'
JSON.parse ''{ "x": "y" }'
# => {"x"=>"y"}
The parse! variant can be used for safe sources. There are also other gems, which may be faster than the default implementation. Please refer to multi_json for the list.
Rails
Modern versions of Rails use multi_json, a gem that automatically uses the fastest JSON gem available. Thus, the recommended way is to use
object = ActiveSupport::JSON.decode json_string
Please refer to ActiveSupport::JSON for more information. In particular, the important line in the method source is
data = MultiJson.load(json, options)
Then in your Gemfile, include the gems you want to use. For example,
group :production do
gem 'oj'
end
This can be done as below, just need to use JSON.parse, then you can traverse through it normally with indices.
#ideally not really needed, but in case if JSON.parse is not identifiable in your module
require 'json'
#Assuming data from bitly api is stored in json_data here
json_data = '{
"errorCode": 0,
"errorMessage": "",
"results":
{
"http://www.foo.com":
{
"hash": "e5TEd",
"shortKeywordUrl": "",
"shortUrl": "http://whateverurl",
"userHash": "1a0p8G"
}
},
"statusCode": "OK"
}'
final_data = JSON.parse(json_data)
puts final_data["results"]["http://www.foo.com"]["shortUrl"]
Ruby's bundled JSON is capable of exhibiting a bit of magic on its own.
If you have a string containing JSON serialized data that you want to parse:
JSON[string_to_parse]
JSON will look at the parameter, see it's a String and try decoding it.
Similarly, if you have a hash or array you want serialized, use:
JSON[array_of_values]
Or:
JSON[hash_of_values]
And JSON will serialize it. You can also use the to_json method if you want to avoid the visual similarity of the [] method.
Here are some examples:
hash_of_values = {'foo' => 1, 'bar' => 2}
array_of_values = [hash_of_values]
JSON[hash_of_values]
# => "{\"foo\":1,\"bar\":2}"
JSON[array_of_values]
# => "[{\"foo\":1,\"bar\":2}]"
string_to_parse = array_of_values.to_json
JSON[string_to_parse]
# => [{"foo"=>1, "bar"=>2}]
If you root around in JSON you might notice it's a subset of YAML, and, actually the YAML parser is what's handling JSON. You can do this too:
require 'yaml'
YAML.load(string_to_parse)
# => [{"foo"=>1, "bar"=>2}]
If your app is parsing both YAML and JSON, you can let YAML handle both flavors of serialized data.
require 'json'
out=JSON.parse(input)
This will return a Hash
require 'json'
hash = JSON.parse string
work with the hash and do what you want to do.
The Oj gem (https://github.com/ohler55/oj) should work. It's simple and fast.
http://www.ohler.com/oj/#Simple_JSON_Writing_and_Parsing_Example
require 'oj'
h = { 'one' => 1, 'array' => [ true, false ] }
json = Oj.dump(h)
# json =
# {
# "one":1,
# "array":[
# true,
# false
# ]
# }
h2 = Oj.load(json)
puts "Same? #{h == h2}"
# true
The Oj gem won't work for JRuby. For JRuby this (https://github.com/ralfstx/minimal-json) or this (https://github.com/clojure/data.json) may be good options.
RUBY is case sensitive.
require 'json' # json must be lower case
JSON.parse(<json object>)
for example
JSON.parse(response.body) # JSON must be all upper-case
Here's what I would do:
json = "{\"errorCode\":0,\"errorMessage\":\"\",\"results\":{\"http://www.foo.com\":{\"hash\":\"e5TEd\",\"shortKeywordUrl\":\"\",\"shortUrl\":\"http://b.i.t.ly/1a0p8G\",\"userHash\":\"1a0p8G\"}},\"statusCode\":\"OK\"}"
hash = JSON.parse(json)
results = hash[:results]
If you know the source url then you can use:
source_url = "http://www.foo.com".to_sym
results.fetch(source_url)[:shortUrl]
=> "http://b.i.t.ly/1a0p8G"
If you don't know the key for the source url you can do the following:
results.fetch(results.keys[0])[:shortUrl]
=> "http://b.i.t.ly/1a0p8G"
If you're not wanting to lookup keys using symbols, you can convert the keys in the hash to strings:
results = json[:results].stringify_keys
results.fetch(results.keys[0])["shortUrl"]
=> "http://b.i.t.ly/1a0p8G"
If you're concerned the JSON structure might change you could build a simple JSON Schema and validate the JSON before attempting to access keys. This would provide a guard.
NOTE: Had to mangle the bit.ly url because of posting rules.
You can try something like this:
def details_to_json
{
:id => self.id,
:credit_period_type => self.credit_period_type,
:credit_payment_period => self.credit_payment_period,
}.to_json
end