How can I extract a Summoner Name from a JSON response? - ruby-on-rails

I'm playing around with with external APIs from League of Legends. So far, I've been able to get a response from the API, which returns a JSON object.
#test_summoner_name = ERB::Util.url_encode('Jimbo')
#url = "https://na.api.pvp.net/api/lol/na/v1.4/summoner/by-name/#{#test_summoner_name}?api_key=#{RIOT_API_KEY}"
response = HTTParty.get(#url)
#summoner = JSON.parse(response.body)
#summoner_name = #summoner[:name]
The JSON object looks like this:
{"jimbo"=>{"id"=>12345678, "name"=>"Jimbo", "profileIconId"=>1234, "revisionDate"=>123456789012, "summonerLevel"=>10}}
So, I'm able to output the JSON object with my #summoner variable in my view. But when I try to output my #summoner_name variable, I just get a blank string.
For reference, this is my view currently:
Summoner Object: <%= #summoner %><br>
Summoner Name: <%= #summoner_name %>
Any help would be greatly appreciated. I've been stumbling through this process all day now.

Problem
You don't have the hash you think you do. Once you've parsed your JSON, your #summoner instance variable actually contains everything else wrapped under a hash key named jimbo. For example, when using the awesome_print gem to pretty-print your hash, you will see:
require 'awesome_print'
ap #summoner, indent: 2, index: false
{
"jimbo" => {
"id" => 12345678,
"name" => "Jimbo",
"profileIconId" => 1234,
"revisionDate" => 123456789012,
"summonerLevel" => 10
}
}
Solution
To get at the name key, you have to go deeper into the hash. For example, you can use Hash#dig like so:
#summoner_name = #summoner.dig 'jimbo', 'name'
#=> "Jimbo"
If you're using an older Ruby without the Hash#dig method, then you can still get at the value by specifying a sub-key as follows:
#summoner_name = #summoner['jimbo']['name']
#=> "Jimbo"

It migth help if you look your json like this:
{"jimbo"=>{
"id"=>12345678,
"name"=>"Jimbo",
"profileIconId"=>1234,
"revisionDate"=>123456789012,
"summonerLevel"=>10}
}
Then you could just do
#summoner_jimbo_name = #summoner['jimbo']['name']
to get the value:
Jimbo

Related

Stuck with send hash with remote true

I was stuck at a point badly..when I was doing with Rails form_for submit request with remote:true with a hidden field containing array of hashes as below:
<%= f.hidden_field :staff_stat_data, :value =>[{a: "a"} , {b: "b"}] %>
then I am getting hash as a string in parameter like:
"{:a=>\"a\"} {:b=>\"b\"}"
Badly stuck with this.
You're not getting a hash, you're getting a string that kind of looks like a hash.
Remember that each parameter is just a string, that's how data is passed between clients and servers. Rails can sometimes receive an array, but only when the parameter names describe an array (e.g, "user_favourites[]").
If you want to pass a single string that represents an array or hash, you can use JSON to encode/parse the data.
In your view, first change the array to its JSON representation like this:
<%= f.hidden_field :staff_stat_data, :value => [{a: "a"} , {b: "b"}].to_json %>
Then in your controller, change it to a hash by parsing the JSON like this:
staff_stat_data = JSON.parse(params[:staff_stat_data])
This will return you an array, where each element is a hash, just like you want.
You can try this out easily in your Rails console.
json = [{a: "a"} , {b: "b"}].to_json # => "[{\"a\":\"a\"},{\"b\":\"b\"}]"
JSON.parse(json) # => [{a: "a"} , {b: "b"}]

Where returns column name along with value

Here is my code:
<%= DimensionVersion.where(:dimension_id => 1).select("name") %>
I expect to get a list of dimension version names where :dimension_id => 1. There are four in the database.
Instead I get this:
#<ActiveRecord::Relation:0x3d351c8>
EDIT:
I figured out how to return what I wanted (sort of) with this:
<%= DimensionVersion.select("name").where(:dimension_id => 1).all %>
Which returns:
[#<DimensionVersion name: "Default">, #<DimensionVersion name: "Test1">, #<DimensionVersion name: "Test2">, #<DimensionVersion name: "Test3">]
However, I don't want it returned with #<DimensionVersion Name: ... >. I tried removing = from the leading tag, but then nothing returned.
DimensionVersion.where(:dimension_id => 1).select("name")
I think you need the pluck method.
Rewrite the above as:
DimensionVersion.where(:dimension_id => 1).pluck(:name)
Similarly even a higher level construct like collect can be used as:
DimensionVersion.where(:dimension_id => 1).collect(&:name)
Hope this helps.
AR returns Relation so that you can chain conditions etc. If you want the actual results, call #all, #first, #each,... on it:
DimensionVersion.where(:dimension_id => 1).select("name").all
Querying with rails is such a pain in the butt I'm about to abandon the whole framework and go back to php.
You might want to read the guides: Active Record Query Interface.
I was able to get rid of the column names by using the collect method like so:
DimensionVersion.select("name").where(:dimension_id => 1).all.collect { |d| [d.name]}

Encoding UTF-8 in Rails form parameter name

I'm having a problem with my params.
I'm receiving the following parameters:
{"utf8"=>"✓", "authenticity_token"=>"...=", "Portugu\xC3\xAAs"=>{"title"=>"313" } }
In my controller I need to use the key => "Portugu\xC3\xAAs", but first I need it to be in the right form (that is -> Português) and I don't know how can I do that.
EDIT:
Workflow
1. The user saves a language
2. I use that language in a form to save information, like this:
Português[title]
3 . Because the user can have multiple locales in that form (all the locales saved in step 1)
locales.each do |locale|
...
:value => params[locale.key][:title]
The problem is that locale.key ('Português') doesn't match with "Portugu\xC3\xAAs" so it crashes with nil
Can you help me with this?
Thank you
I've tried this, and the result is good:
<% p = {}
p["Português"] = {}
p["Português"][:title] = "Title in Portugês" %>
<p><%= p["Portugu\xC3\xAAs"][:title] %>
And I get
<p>Title in Portugês</p>
I don't see the problem.
The solution that worked for me was iterating the received params and with the help of URI.escape compare the string, if matches enc_locale is set and used in the value.
Thanks to everyone that helped!
enc_locale = ""
params.each do |param|
if URI.escape(param[0]) == URI.escape(locale.key)
enc_locale = param[0]
end
end
...
:value => params[enc_locale][:title]

Explaining hashes in Ruby

I'm reading a book Crafting Rails Applications by Jose Valim and have come across something that I don't understand. I'm wondering if someone can explain the difference in plain English between the three types of hash below.
For example, in what way is the nested hash (as its represented in this example) a nested hash. In other contexts, I understand nested hashes, but don't get it here.
In what way is an "array" a "key" in the second example. To me it looks just like an array with four variables.
In what way is the third example a hash with "hash as key".
Nested hash
#cached[key][prefix][name][partial]
Simple hash with array as key
#cached[[key, prefix, name, partial]]
Simple hash with hash as key
#cached[:key => key, :prefix => prefix, :name => name, :partial => partial]
The nested hash, is well, a nested hash. The example given, #cached[key][prefix][name][partial], is showing you the "path" to a particular value, so in this case the hash might look something like this:
#cache = {
key => {
prefix => {
name => {
partial => "value"
}
}
}
}
For the simple hash with an array as a key, they're using that 4-element array as one of the keys in the hash.
#cache = {
[key, prefix, name, partial] => "value",
another_key => "another value"
}
For the simple hash with hash as a key, they're using that hash (note that the {}'s for the hash are optional, which may cause some confusion) as one of the keys in the hash.
#cache = {
{:key => key, :prefix => prefix, :name => name, :partial => partial} => "value",
another_key => "another value"
}
Hope that helps!
A hash simply associates key objects to value objects. The keys and values can be anything.
If a value object is itself a hash, you could call it a "nested hash" because in some sense it is inside the main hash.
If a key object is an array, then you get a "hash with array as key".
If a key object is itself a hash, then you get a "hash with hash as key".
See amfeng's answer for a good visual representation of these different cases.
You will need to be somewhat familiar with Ruby syntax to identify the different cases when you see them.
For example, to understand #cached[[key, prefix, name, partial]] you need to know that [key, prefix, name, partial] represents an array, so what you have is like #cached[array], which means an array is being used as a key.
When you see something like #cached[key][prefix] you should know that it is equivalent to (#cached[key])[prefix] so the value object (#cached[key]) is some sort of object that responds to the [] method. In this case, it is a nested hash because the author told you so, but if you didn't know that context then it is possible for it to be something else.
When you see something like #cached[:key => key, :prefix => prefix, :name => name, :partial => partial] you should know it equivalent to #cached[{:key => key, :prefix => prefix, :name => name, :partial => partial}], which means we are using as hash as a key.

Ruby on Rails: Interpreting a form input as an integer

I've got a form that allows the user to put together a hash.
The hashes desired end format would be something like this:
{1 => "a", 2 => "x", 3 => "m"}
I can build up something similar by having lots of inputs that have internal brackets in their names:
<%= hidden_field_tag "article[1]", :value => a %>
However, the end result is that builds a hash where all the keys are strings and not integers:
{"1" => "a", "2" => "x", "3" => "m"}
I'm currently fixing this by generating a new hash in the controller by looping over the input hash, and then assigning that to params. Is there a cleaner, DRYer way to do this?
Your params will always come in with string keys and values. The easiest way to fix this is to either write your own extension to Hash or simply inject as required:
numeric_keys = params['article'].inject({ }) do |h, (k, v)|
h[k.to_i] = v
h
end
Then you have a hash with the keys converted to integer values, as you like.
A simple extension might be:
class Hash
def remap_keys
inject({ }) do |h, (k, v)|
h[yield(k)] = v
h
end
end
end
This is much more generic and can be used along the lines of:
params['article'].remap_keys(&:to_i)
That depends a bit what you want to use it for. Maybe it is easier to just use strings as keys, and do the "conversion" when accessing the array (or not at all)?
It is also possible to build an array using something like
<%= hidden_field_tag "article[]", :value => "x" %>
this will return "article" as an array, and you can access it directly by index. However, there is no way to influence the position - the array will contain all values in order of appearance.
Lastly, you can make your own version of Hash or just modify the keys, as has been explained.

Resources