Generating json structures using ERB template - ruby-on-rails

Json1:
{
"Name1" : "Value1",
"Name2" : "<%= Value2 %>"
}
Value2 is calling a method which reads json2 and gives an output.
ERB.new(File.read("json1.json")).result gives me the output of second json file and not the json1.
I can not figure out how else can I replace the value 2 with the output of second json. Is there a way I can pass the value of already evaluated json for Value2?

This shows your problem:
ERB.new( "foo bar <%= ERB.new( 'baz' ).result %>" ).result
=> "baz"
This is nothing to do with JSON. It's because ERB does not nest automatically, due to how the template is evaluated. It appends to a variable called :_erbout, and different ERB objects will use the same variable. It's fine when you want to build up a structure sequentially, but not so great for nested includes.
You can fix your problem by telling ERB to use a different named variable when generating output:
ERB.new( "foo bar <%= ERB.new( 'baz', nil, nil, :_erbout2 ).result %>", nil, nil, :_erbout1 ).result
=> "foo bar baz"
The code is starting to look ugly so you might want to abstract it (especially if you don't know in advance how deep the nesting will go, so you'll want to generate the variable names)

Related

passing an array to a rails button_tag

the following
#ids.class
is being properly returned as Array
But when it is being used as values
<%= button_tag 'Top', value: #ids, type: :submit, name: :top %>
the params submitted are:
"top"=>"17515 30784 31614 32342 32362 31815 31813 32386 33004 32483 31750 32478 16331 11728"
which is a string.
> params[:top].class
String
Transforming via Array(params[:top]) only results in a single element
["17515 30784 31614 32342 32362 31815 31813 32386 33004 32483 31750 32478 16331 11728"]
Transforming via substitution of space with a comma, to then generate a proper array
params[:top].sub(" ", ",")
only handles the first space
"17515,30784 31614 32342 32362 31815 31813 32386 33004 32483 31750 32478 16331 11728"
Modifying the tag to value: #ids.to_s returns the same situation.
How can this be properly processed by the subsequent action as an array?
How can this be properly processed by the subsequent action as an array?
Unless you want to do some wonky parameter processing like params[:top].split(' ') you need to use multiple parameters in a form or query string to pass an array.
To pass array parameters in Rack (the CGI that Rails sits on top of) you need to pass multiple formdata pairs where the key ends with [].
foo[]=1&foo[]=2&foo[]=3
# resulting params hash
=> { "foo" => ["1", "2", "3"] }
This is actually processed the same way regardless if its passed in the query string or request body.
For query strings #to_query handles this automatically:
irb(main):004:0> CGI.unescape( { foo: [1,2,3]}.to_query )
=> "foo[]=1&foo[]=2&foo[]=3"
For forms you can just create hidden inputs:
<% values.each do |v| %>
<%= hidden_field_tag 'top[]', v %>
<% end %>
Max's answer is correct but will use n hidden form fields to generate the foo[]=1&foo[]=2&foo[]=3 response.
If you still want to use it with the button_tag input field you can do something like the following
# In your form file
<%= button_tag 'Top', value: #ids, type: :submit, name: :top %>
And then use it like that in your controller
# Use #split on the string params
params[:top].split
Example
"10 20 30".split => ["10", "20", "30"]
You can always pass a delimiter to split by on the #split method
#split documentation

How can I extract a Summoner Name from a JSON response?

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

Rails interpolate action_name

I have the following code structure:
<% types = [
{
one: 'one 1',
two: 'two 2',
three: 'three 3'
}
] %>
<% result = types[:#{action_name}]%>
<% puts result %>
The one, two and three are actions I have, which I want to interpolate in the result variable, so the result of an action would get the according object in the types array. How can I do this, what I did seems to return an error.
:#{action_name} it returns an error
Your code is wrong syntactically.
Fix is : :"#{action_name}" . And you don't need a Array of hash, only hash is enough.
<% types =
{
one: 'one 1',
two: 'two 2',
three: 'three 3'
}
%>
There is a couple of things wrong with your solution.
1) types = [{ one: "one1", ... }] is not a hash, it is an array with a hash in it. It looks like you want a hash, so it should be written as types = { one: "one1", ... }
2) You want to access an element from the hash by effectively doing types[:one]. To interpolate a variable into a symbol you need to do use the quotes, i.e. :"#{var}". So the assignment line should be result = types[:"#{action_name}"]
3) It seems you are doing this in a template, which is a strange place to variable assignment of any sort. I suggest you move all this code into a controller (for a start, at least).
If you have array of hash then you can access first array element:
types.first[:"#{action_name}"]
Or you can use loop for accessing hash.
If you need only hash then you should follow #Arup Rakshit answer.

Ruby - link_to - How to add data directly from DB

First of all, I am very new to ruby and I am trying to maintain an application already running in production.
I have been so far able to "interpret" the code well, but there is one thing I am stuck at.
I have a haml.html file where I am trying to display links from DB.
Imagine a DB structure like below
link_name - Home
URL - /home.html
class - clear
id - homeId
I display a link on the page as below
< a href="/home.html" class="clear" id="home" > Home </a>
To do this I use 'link_to' where I am adding code as follows
-link_to model.link_name , model.url, {:class => model.class ...... }
Now I have a new requirement where we have a free text in DB, something like -
data-help="home-help" data-redirect="home-redirect" which needs to come into the options.
So code in haml needs to directly display content versus assign it to a variable to display.
In other words I am able to do
attr= '"data-help="home-help" data-redirect="home-redirect"' inside the <a>, but not able to do
data-help="home-help" data-redirect="home-redirect" in <a> tag.
Any help would be greatly appreciated!
link_to accepts a hash :data => { :foo => "bar" } of key/val pairs that it will build into data- attributes on the anchor tag. The above will create an attr as follows data-foo="bar"
So you could write a method on the model to grab self.data_fields (or whatever it's called) and split it into attr pairs and then create a hash from that. Then you can just pass the hash directly to the :data param in link_to by :data => model.custom_data_fields_hash
This somewhat verbose method splits things out and returns a hash that'd contain: {"help"=>"home-help", "redirect"=>"home-redirect"}
def custom_data_fields_hash
# this would be replaced by self.your_models_attr
data_fields = 'data-help="home-help" data-redirect="home-redirect"'
# split the full string by spaces into attr pairs
field_pairs = data_fields.split " "
results = {}
field_pairs.each do |field_pair|
# split the attr and value by the =
data_attr, data_value = field_pair.split "="
# remove the 'data-' substring because the link_to will add that in automatically for :data fields
data_attr.gsub! "data-", ""
# Strip the quotes, the helper will add those
data_value.gsub! '"', ""
# add the processed pair to the results
results[data_attr] = data_value
end
results
end
Running this in a Rails console gives:
2.1.2 :065 > helper.link_to "Some Link", "http://foo.com/", :data => custom_data_fields_hash
=> "<a data-help=\"home-help\" data-redirect=\"home-redirect\" href=\"http://foo.com/\">Some Link</a>"
Alternatively you could make it a helper and just pass in the model.data_attr instead
link_to "Some Link", "http://foo.com/", :data => custom_data_fields_hash(model.data_fields_attr)
Not sure you can directly embed an attribute string. You could try to decode the string in order to pass it to link_to:
- link_to model.link_name, model.url,
{
:class => model.class
}.merge(Hash[
str.scan(/([\w-]+)="([^"]*)"/)
])
)

haml select_tag with constants

I'm new to Ruby and Haml, so I"m going around in circles on this. Googling isn't giving me any sample code I can use.
I can use the select_tag and populate the list from a table. But I can't figure out how to use a simple static list of items. Can someone change this to be proper Haml? Note: the source table is 'email' and the field is 'status'.
= select_tag(:email, :status, {"canceled", "pending", "success"})
I'm looking to get a dropdown list that just has the items "canceled, pending, success" in it.
The error I get is odd number list for Hash._hamlout.format_script...
Update: I found some sample code that seemed to be what I need, and it doesn't give any errors, but the dropdown box is empty:
= select_tag(:email, :status,{ "canceled" => "1", "pending" => "2", "success"=>"3"})
Here is the HTML it produces:
<select female="2" male="1" id="email" name="email">status </select >
You are using the tag helper rather than the object-oriented helper. Use select
I'd also recommend using options_for_select. Like so:
= select(:email, :status, options_for_select([["canceled", "1"], ["pending", "2"], ["success", "3"]]))
See:
http://apidock.com/rails/ActionView/Helpers/FormOptionsHelper/select
http://apidock.com/rails/ActionView/Helpers/FormOptionsHelper/options_for_select
Got it working! I need to use "Select" instead of "Select_tag". :-)
= select(:email, :status,{ "canceled" => "canceled", "pending" => "pending", "success"=>"success"})

Resources