Stuck with send hash with remote true - ruby-on-rails

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"}]

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 passing in variables into view helper methods from form selection

I have a bit of code in my user.rb model like this:
def self.aggregate(articles)
array = []
articles.each do |a|
array << {
:id => a.nid,
:views => a.daily_view_metrics.sum_views(a.nid),
:date => a.daily_view_metrics.latest_date(a.nid),
:title => a.daily_view_metrics.latest_title(a.nid),
:visits => a.daily_view_metrics.sum_visits(a.nid)
}
end
return array
end
In my user_controller I pass into the show method #metrics = User.aggregate(#articles) (#articles being simply a subset of articles for that user)
Now in my view (user#show) i call #metrics.each do |m| and then output all the different things in a table. Now according to this video it seems that the link_to method with a url parameter seems to be the best way to have users dynamically switch what they want to sort against.
How can I input that url parameter to sort the array? I tried calling #metrics.sort_by{|h| h[params[:sort]]}.each do |m| with :sort being the url parameter from my links (i.e. the views table header link click passes :sort => ":views" in. Essentially I am trying to do this sort_by{|h| h[:views]} since that works fine for sorting the array. However nothing happens. The array isn't sorted.
EDIT:
I solved it by making the aggregate method pass the key in as a string (i.e. "id" as opposed to :id). then the url params works beautifully.
<%= link_to "Views", :sort => "views"%> now sorts it by views in ascending order.
To order in descending mode you can negate - the element that you are using to sort by.
Ordering by ascending and then do revert to your collection is inefficient.
For instance
$> [{a: 'a1', b: 1}, {a: 'a2', b: 2}].sort_by{ |h| -h[:b] }
# => [{:a=>"a2", :b=>2}, {:a=>"a1", :b=>1}]
$> [{a: 'a1', b: 1}, {a: 'a2', b: 2}].sort_by{ |h| h[:b] }
# => [{:a=>"a1", :b=>1}, {:a=>"a2", :b=>2}]
In the form of your view, you will have something like this (a RadioButton e.g but it could be a Select or whatever you prefer):
<%= radio_button_tag 'radio_order', 'ascending', true %> Ascending
<%= radio_button_tag 'radio_order', 'descending' %> Descending
<%= submit_tag "Order" %>
Then in your helper get the value using params[:radio_order]:
aggregate('views', params[:radio_order])

convert array of parameters from form into string

I have a form with a checkboxes:
-form_tag filter_path(#page.permalink), :method => 'get' do |f|
-ftype.producers.each do |producer|
=check_box_tag "producers[]", producer.id, false
=label_tag producer.title
%br
=submit_tag 'Сортувати', :name => nil
When I send a request, it sends a hash params with an array of producers.Link then looks like that:
'/pages/:page_id/filter?producers[]=4&producers[]=5'
And I want to make it look that:
'/pages/:pages_id/filter?producers=4,5'
Please help
It shouldn't be a problem, since ?producers[]=4&producers[]=5 will be converted by the framework into params[:producers] array with value [4, 5].
Thus, you already have an array and you don't even have to parse anything.
But if your really want to submit two input values in one parameter, you'd have to employ some javascript. By default, if you have in html form two inputs with the same name, two independent values will be submitted (like in sample url you provided).
So, it's not a Rails question, it's html and javascript question.

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