Rails interpolate action_name - ruby-on-rails

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.

Related

How do I parse this array of hashes?

I have the following array of hashes and I need to parse all email that are not empty:
[{:id=>"something", :first_name=>"First", :last_name=>"Name", :name=>"First Name", :email=>"first_name#gmail.com", :gender=>nil, :birthday=>nil, :profile_picture=>nil, :relation=>nil},
{...},
{}]
I am trying to do that this way:
- #contacts[0].each_with_index do |c, i|
- unless c[:email].blank?
%tr
%td= c[:email]
%td= check_box_tag "email_to[]", c[:email], true
But I am getting error:
An ActionView::Template::Error occurred in users#parse_data:
no implicit conversion of Symbol into Integer
How to do it right?
It's not good design to do a lot of processing in your views. It's understandable to have simple conditionals and loops, but heavy processing should occur in the controller.
Use something along these lines:
ary = [
{:id=>"something", :first_name=>"First", :last_name=>"Name", :name=>"First Name", :email=>"first_name#gmail.com", :gender=>nil, :birthday=>nil, :profile_picture=>nil, :relation=>nil},
{:id=>"something", :first_name=>"First", :last_name=>"Name", :name=>"First Name", :email=>"", :gender=>nil, :birthday=>nil, :profile_picture=>nil, :relation=>nil},
{}
]
viewable_email = ary.reject{ |e| e.empty? || e['email'].empty? }
At this point viewable_email would contain only the hashes to be displayed. Your view would only loop over them.
#contacts.each_with_index do |c, i| ...
When you say each_with_index on a hash you will get an array like below
{:id=>"something", :first_name=>"First", :last_name=>"Name"}.each_with_index{|e,i| p e}
[:id, "something"]
[:first_name, "First"]
[:last_name, "Name"]
So, you cant say e[:id], thats why the error. As mentioned above #contacts[0] will give you the hash and not an array.

Generating json structures using ERB template

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)

Ruby on Rails get key by value from two dimensional array

I have a two dimensional array that looks like this:
TITLETYPE = [['Prof.', '4'],
['Dr.', '3'],
['Mrs.', '2'],
['Ms.', '1'],
['Mr.', '0']]
I need to get the key for value 1 for example (which should be 'Ms.')
How should I go about doing that?
TITLETYPE.select{ |x| x[1] == '1' }.first.first
How this works
You can use Array's select method to find the row you're looking for. Your rows ar arrays with two elements each (element 0 and element 1), so you need to look for the row in which the second element (element 1) is equal to the value you're looking for (which is the string "1"):
TITLETYPE.select{ |x| x[1] == "1" }
This will return an array with only one row:
[["Ms.", "1"]]
To get the first and only value from that array, use Array's first method, which will return:
["Ms.", "1"]
Then, from that, obtain the first value from the two values with first again:
"Ms."
Actually, sounds like Array#rassoc is perfect for you.
TITLETYPE.rassoc('1')[0] # => 'Ms.'
See the documentation at Ruby-doc.
More naturally, you should keep such information as a hash. If you often want key-to value, and key-to value is unique, then create a hash:
TYTLETYPEHASH = Hash[TYTLETYPE.map(&:reverse)]
and access it:
TYTLETYPEHASH['1'] # => 'Ms.'
or create a hash like:
TYTLETYPEHASH = Hash[TYTLETYPE]
and access it:
TYTLEHASH.key('1') # => 'Ms.'
I had a similar issue, and resolved it by simply using something like this:
<% Array.each do |value| %>
and accessing each element using <%= value[:keyname] %>
i.e.
An array which looks like this (using .inspect)
[{:id=>1, :title=>"ABC"}, {:id=>2, :title=>"XYZ"}]
can become a HTML selection/dropdown box with:
<select name="ClassName[TargetParameter]">
<% Array.each do |value| %>
<option value="<%= value[:id] %>"><%= value[:title] %></option>
<% end %>
</select>

Ruby - bad output from arrays

I have a form with a lots of these text inputs:
<%= text_field_tag 'name[seq]['+dat.id.to_s+']', dat.seq%>
After send this form I want to save them to database, I try to get the values from inputs in each loop:
unless params[:name].nil?
params[:name][:seq].each_with_index do |sq, i|
puts sq
end
end
But the output in terminal is wrong, for example if I have an input with the values
<%= text_field_tag 'name[seq][25]', 3%>
So I am going to expect the output is 3, but I will get to terminal this:
25
3
Is here something important, what I don't see?
Yes, you are missing something. Within your each_with_index block, sq will be an array and that's why you get that output.
So, what's going on here? Well, your params will contain this:
"name" => { "seq" => { "25" => "3" } }
And that means that params[:name][:seq] is this:
{ "25" => "3" }
Then you apply each_with_index to that to iterate through the Hash. If you do it like this:
params[:name][:seq].each_with_index do |(k,v), i|
puts "-#{k}-#{v}-"
end
you'll see what's going on.
If you just want the 3 then you can iterate over params[:name][:seq] as above and just look at v inside the block or, if you know what the '25' is some other way, you could just go straight there:
three = params[:name][:seq]['25']

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