Ruby - bad output from arrays - ruby-on-rails

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']

Related

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.

Rails : can't convert Regexp into Integer

I have the following code in my rails controller:
#main_mastertest = $connection.execute("SELECT * FROM builds;")
#l2_tmp_mastertest = Array.new
#l2_tmp_mastertest = #main_mastertest.map {|y|[y[0]]}
#l2_mastertest = Array.new
#l2_mastertest = #l2_tmp_mastertest.inject(Hash.new(0)) { |hash,element|
hash[element] +=1
hash }
#l2_mastertest = #l2_mastertest.sort_by { |x, _| x }.reverse
After that I try to do something like this in my view :
<% #l2_mastertest.each_with_index do |row1, index1| %>
<% #l2_mastertest.each_with_index do |row2, index2| %>
<% if row2[0][ /(\d+\.\d+)/ ].to_s == row1[0].to_s %> # LINE X
..................
<% end %>
<% end %>
<% end %>
But it gives me an error on line X saying : can't convert Regexp into Integer
If I simulate what I think is going on with the data structures in your question, I get this:
#l2_mastertest = { '3.1.4' => 7, '1.2.3' => 8 }
=> {"3.1.4"=>7, "1.2.3"=>8}
#l2_mastertest.each_with_index { |row2,index| p row2,index }
["3.1.4", 7]
0
["1.2.3", 8]
1
So a structure like row2[0][ /(\d+\.\d+)/ ] is the same as e.g. "3.1.4"[ /(\d+\.\d+)/ ]
Edit: Removed my previous "answer", because actually "3.1.4"[ /(\d+\.\d+)/ ] => "3.1", which is fine in Ruby (and I learned something today :-). Something else (possibly in code not shown) is making the #l2_mastertest hash not behave as expected.
Potentially this is a database/model issue, and as commenters have suggested, row[0] does not contain a string.
I would suggest instead that SELECT * FROM builds; is risky, since you are relying on database to return columns in particular order. You should change it to fetch the column data you need, in order e.g.
SELECT version, result, build_id FROM builds;
so that you are certain that later processing is working with the column that you think it is. Simply re-building or transferring the database could change the order that the RDBMS returns the columns in a SELECT * and make previously-working code break.

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>

How to display Rails select field values rather than stored integers in other views

I'm using a select field in a Rails app that is NOT tied to a related model, but stores integer values for a static series of options , i.e.,
<%= select (:this_model, :this_field, [['Option1',1],['Option2',2],['Option3',3],['Option4',4]] ) %>
In a show/ index view, if I want to display the option text (i.e. Option1, Option2, etc) rather than the integer value stored in the database, how do I achieve this?
Thanks for helping a noob learn the ropes!
EDIT
Based on Thorsten's suggestion below, I implemented the following. But it is returning nil, and I can't figure out why.
Invoice model:
##payment_status_data = { 1 => "Pending Invoice" , 2 => "Invoiced" , 3 => "Deposit Received", 4 => "Paid in Full"}
def text_for_payment_status
##payment_status_data[payment_status]
end
Invoice show view:
Payment Status: <%= #invoice.text_for_payment_status %>
In the console:
irb > i=Invoice.find(4)
=> [#<Invoice id: 4, payment_status: 1 >]
irb > i.text_for_payment_status
=> nil
I've tried defining the hash with and without quotes around the keys. What am I missing?
something like this would work:
<%= form_for #my_model_object do |form| %>
<%= form.label :column_name "Some Description" %>
<%= form.select :field_that_stores_id, options_for_select({"text1" => "key1", "text 2" => "key2"}) %>
<% end %>
Update
If you later want to display the text you can get it from a simple hash like this:
{"key1" => "text 1", "key2" => "text2"}[#my_object.field_that_stores_id]
But you better store this hash somewhere in a central place like the model.
class MyModel < ActiveRecord
##my_select_something_data = {"key1" => "text 1", "key2" => "text2"}
def text_for_something_selectable
##my_select_something_data[field_that_stores_id]
end
end
Then you can use it in your views like
#my_object.text_for_something_selectable
There are many possible variations of this. But this should work and you would have all information in a central place.
Update
Ok, I used something similar for our website. We need to store return_headers for rma. Those need to store a return reason as a code. Those codes are defined in an external MS SQL Server Database (with which the website exchanges lots of data, like orders, products, and much more). In the external db table are much more return reasons stored than I actually need, so I just took out a few of them. Still must make sure, the codes are correct.
So here goes he model:
class ReturnHeader < AciveRecord::Base
##return_reason_keys = {"010" => "Wrong Produc",
"DAM" => "Damaged",
"AMT" => "Wrong Amount"}
def self.return_reason_select
##return_reason_keys.invert
end
def return_reason
##return_reason_keys[nav_return_reason_code]
end
end
Model contains more code of course, but that's the part that matters. Relevant here is, that keys in the hash are strings, not symbols.
In the views i use it like this:
In the form for edit:
<%= form_for #return_header do |form| %>
<%= form.label :nav_return_reason_code "Return Reason" %>
<%= form.select :nav_return_reason_code, options_for_select(ReturnHeader.return_reason_select, #return_header.nav_return_reason_code) %>
<% end %>
(Maybe no the most elegant way to do it, but works. Don't know, why options_for_select expects a hash to be "text" => "key", but that's the reason, why above class level method returns the hash inverted.)
In my index action the return reason is listed in one of the columns. There I can get the value simply by
#return_headers.each do |rh|
rh.return_reason
end
If you have trouble to get it run, check that keys a correct type and value. Maybe add some debug info with logger.info in the methods to see what actual data is used there.

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