Passing an array of arrays from a form - ruby-on-rails

I'm implementing a form based on Ryan Bate's [always excellent] Railscast, #52, Update Through Checkboxes, http://railscasts.com/episodes/52-update-through-checkboxes
In my case, I'm actually wanting to pass through an array of ids for each checkbox selected.
The key line in my form looks like this,
<td"><%= check_box_tag "sales_ids[]", batch["sales_ids"] %></td>
batch["sales_ids] itself is an array of ids, and the outcome I'm wanting is for an array of all the checked items (each representing an array of ids) to be passed along.
If I inspect the individual batch["sales_ids"] from the form, then I can confirm it is indeed an array, for example, [3907, 3908, 3909] (remember, I want to pass along an array of these items for each row checked)
The key line from the method that handles the form looks like this,
params[:sales_ids].each { |batch| Sales.update_all(["code=?", 99], :id => batch) }
The intent of this code, again based on the Railscast example, is to iterate over the array of arrays, and update each sub-array of ids.
When I examine the received array, I see, ["5412", "3907 3908 3909", "2452"]
The sub-array isn't handled as an array and (for reasons I don't understand) only the first item each 'substring' (in this case "5412", "3907", "2452") is updated.
It seems that the passed subarray isn't actually an array, or something else is awry.
I'd appreciate help in how to pass and receive these ids as an array of arrays. Thanks.

as far as I know, passing arrays of arrays in this way won't work via a form. However there is a work around that should work fine for you.
in the view do this for your checkboxes: (I'm assuming batch["sales_ids"] is an array)
<%= check_box_tag "sales_ids[]", batch["sales_ids"].join(",") %>
And in your controller do this:
params[:sales_ids].collect{|a| a.split(",") }.each { |batch| Sales.update_all(["code=?", 99], :id => batch) }
Instead of passing an array of arrays, we are now passing an array of comma separated values. In the controller these comma separated values are turned into an array.

Related

How to extract the value from a key pair array?

I have an array with keys that I use to create options for a drop down
FEEDBACK_NOTIFICATION = [['Only in reports', 'only_in_reports'],['Immediately', 'immediately']]
<%= f.select(:feedback_schedule, options_for_select(FEEDBACK_NOTIFICATION)) %>
The first values ('Only in reports', 'Immediately') are displayed in the drop down but the last value is stored in the database ('only_in_reports' or 'immediately').
When I want to show the value in a view I am doing something like this:
REPORT_SCHEDULE.select {|v,k| k==#company.report_schedule}.first.first
Is there not an easier way to retrieve a value from a key pair array?
Slightly better:
REPORT_SCHEDULE.find { |v, k| k == #company.report_schedule }.first
Personally, I would however store the "translations" in a yaml file, following the I18n conventions, as shown in my answer on question Translating activerecord collection for a dropdown
This way, your "representation" is nicely separated from the rest of your code
This should do.
Hash[REPORT_SCHEDULE][#company.report_schedule]

how do I get a count of an array based on a nested attribute?

I have a user array with an invitations_attributes array inside of it. The invitations_attributes array has another array inside of it. Here is the structure:
"user"=>{"invitations_attributes"=>{"6"=>{"email"=>""}, "7"=>{"email"=>""}, "0"=>{"email"=>"asdf#gmail.com"}, "1"=>{"email"=>""}, "2"=>{"email"=>""}, "3"=>{"email"=>""}, "4"=>{"email"=>""}, "5"=>{"email"=>""}}}}
What I want to do is get a count of invitations_attributes where the email value is not blank. So in the above case, the count would be 1.
What you show is a nested hash, not an array. Given a user hash as you describe:
user["invitation_attributes"].count{ |key, value| value["email"].present? }

jRuby / Rails sort hash by another hash value

I have a hash that will render my html differently based on a particular variable. The variable is within the hash. So I am wondering how I can pass a hash value to a group by. to sort the rest heres what I am trying, maybe this will explain it better than me wording it.
<% grouped = svcs.group_by { |svc| svc[val[:sorttype]] } %>
val is a multidimensional hash. the first 2 key value pairs sorttype and one other are simple key and value, the 3rd piece (svcs) contains the equivilent of a 2D hash. Which if I manually type the type of sort I want to apply to it for the group by it works ie:
<% grouped = svcs.group_by { |svc| svc[:service_name] } %>
in PHP i know in a similar instance I can pass a variable of some sort to something like this and have it work. I assume such is the case here. However Im not sure how to put the variable in. Cause all the ways Ive tried don't work
It depends a little.
Rails' has a HashWithIndifferentAccess that will not distinguish between string and symbol keys; if you're using one of those, it should work as-is.
If it's not, it depends what the val entries are--if they're strings, convert to a symbol using to_sym, e.g., svc[val[:sorttype].to_sym].

Ruby on Rails 3: sort array based on data from ActiveRecord

I have one array, which are IDs from one ActiveRecord table.
so I would like to sort that array based on last name which is associated with that ID...how can I do that?
To clarify:
array #students=[], inside are IDs and I would like to sort by Student.find(ID).last
Thank you.
Dorijan
Without fully understanding the question, if you're given a list of id's, you can sort by last_name when you're doing the query:
Student.where("id IN (?)", #students).order(:last_name)
Of course, this assumes that #students is an array of ids and nothing else.
Responding to your comment, I'm not sure why you'd need to do that, but if your #student array is just a list of ids ignorant of the Student model and its attributes, and you would still like to order that array, you can do this:
#students = Student.where("id IN (?)", #students).order(:last_name).collect(&:id)
This will return an array of ids sorted by last name. But again, I don't really know what you have going on behind the scenes, and I'm not sure what you're asking for.
Based on your comment, you want to do the following:
Take in a list of IDs of students as input
Return a list of IDs ordered by the student's last name in the database.
You should be able to do the following:
Student.where(:id => #ids).order(:last_name).map(&:id)
Breaking this down:
where(:id => #ids) only selects Students with an ID in the ID array.
order(:last_name) sorts the results by last name.
map(&:id) takes in an array of Students and returns just the ID column. Essentially, the method in brackets (which is a shortcut for calling id for each student) is called for each student found, and the return values are assembled into a new array (which will only contain the ids).
Some gotchas:
If an ID doesn't exist in the database, it will be excluded from the results - if your result array is smaller than your input array, you may be trying to access a record that no longer exists.
If the Students table has a lot of columns, you may want to consider calling select(:id) so that you don't pull every column of the Student records from the database.
Student.find( #students ).sort_by { |s| s.last_name }

get first value in hash within hash

Is there a simple way, instead of looping my entire array to fetch the first value of every inner array.
so in essence I have the following;
array = [['test', 'test2'...], ['test' ....]]
so I want to grab array[#][0] and store the unqiue values.
EDIT
Is there a similar way to use the transpose method for arrays with Hash?
I essentially want to do the same thing
Hash = {1=> {1=> 'test', .....}, 2=> {1=> 'test',....}
so at the end I want to have something like new hash variable and leave my existing hash within hash alone.... = {1 => 'test', 2=> 'test2'}
Not sure if I fully understand the question, but if you have a 2 dimensional array (array in array), and you want to turn that into an array of the first element of the second dimension, you can use the map function
firsts = array.map {|array2| array2.first}
The way map works is that it turns one collection into a second collection by applying a function you provide (the block) to each element.
Maybe this?
array.transpose[0]

Resources