0

I am getting a no of hashes in my controller which are submitted as part of form data.The form basically contains a list of tasks ie task name ,task type etc each of which is getting submitted a hash.The hashes look like this.Task name hash

{"task_1_name"=>"This is task no 1", "task_2_name"=>"This is task no 2", "task_3_name"=>"This is task no 3", "task_4_name"=>"This is task_no_4"...}

and there is task type hash

{"task_1_type"=>"T","task_2_type"=>"M","task_3_type"=>"D","task_4_type"=>"M"...}

What i want is single active record like http://textuploader.com/dr880. Any suggestions would be great help. Have spent hours looking for solution but could not find any thing like this

Artjom B.
  • 61,146
  • 24
  • 125
  • 222
yogeshmanjhi
  • 335
  • 1
  • 4
  • 17
  • @moveson for all the records i want :id, task_name,:task_type.have corrected the pic – yogeshmanjhi May 08 '17 at 02:05
  • Is the order of the key/value pairs in each hash dependent on the key names or the actual order in which the key/value pairs appear? In other words, is there actually a number within each key that indicates the correct order in which the pairs should be sorted, as shown in the question, or do the actual names have no relation to their order? – moveson May 08 '17 at 02:17
  • Also, is it possible for a key to be skipped in one hash but not the other? For example, might the name hash skip from `task_4_name` to `task_6_name` while the type hash contains `task_4_type`, `task_5_type`, `task_6_type`? – moveson May 08 '17 at 02:20
  • @moveson the order is important for example task_1_name and task_1_type means the data is associated with task no 1. The data belong to form see this link https://unsee.cc/rigomenu/ – yogeshmanjhi May 08 '17 at 02:29
  • OK, but is the actual name of the key for the first task `task_1_name`? Or is it just `task_name`? Or is it something else? – moveson May 08 '17 at 02:48
  • @moveson the actual name of key for first task is task_1_name so that i can identify that its the name from first task.i need a single active record so that i can iterate over it and save all the tasks in task table – yogeshmanjhi May 08 '17 at 03:01
  • This seems like more of an issue with your form design than anything else. While you can solve it as described below fixing your form to submit the correct data would make everything far easier something like `tasks[1][task_name]` and `tasks[1][task_type]` as input names should solve this for you as they will become `tasks: [{task_name: '', task_type: ''},{...}]` when submitted – engineersmnky May 08 '17 at 13:22

1 Answers1

0

The most significant issue is you need to make sure you have the task names and task types correctly matched. That matching process will need to happen either by using the positions within the hashes or by matching based on keys that contain ordering information.

Hashes in Ruby 1.9+ are ordered, so it is possible to rely on position, but it would add some certainty if we could rely on ordering information in the keys themselves. Assuming the keys you receive actually contain sequential numbers as shown in the example, you can start by indexing each hash based on that number. First we'll assign the hashes to variables:

>> name_hash = {"task_1_name"=>"This is task no 1", "task_2_name"=>"This is task no 2", "task_3_name"=>"This is task no 3", "task_4_name"=>"This is task_no_4"}
>> type_hash = {"task_1_type"=>"T","task_2_type"=>"M","task_3_type"=>"D","task_4_type"=>"M"}

Next we'll index each hash based on the sequential number. We can extract that number using the String#split method, picking the second element, and converting it to an integer so it sorts properly if the numbers go beyond a single digit:

>> indexed_name_hash = name_hash.index_by { |k,_| k.split('_').second.to_i }
-> {1=>["task_1_name", "This is task no 1"], 2=>["task_2_name", "This is task no 2"], 3=>["task_3_name", "This is task no 3"], 4=>["task_4_name", "This is task_no_4"]}
>> indexed_type_hash = type_hash.index_by { |k,_| k.split('_').second.to_i }
-> {1=>["task_1_type", "T"], 2=>["task_2_type", "M"], 3=>["task_3_type", "D"], 4=>["task_4_type", "M"]}

Now that we have a reliable way to pair names with types, we'll use Array#map to build our desired attributes. Hash#keys gives us just the keys of one of our hashes, which in this example will be [1, 2, 3, 4]. We then map those integers to the values of the respective data:

>> paired_attributes = indexed_name_hash.keys.map { |number| {task_name: indexed_name_hash[number].last, task_type: indexed_type_hash[number].last} }
-> [{:task_name=>"This is task no 1", :task_type=>"T"}, {:task_name=>"This is task no 2", :task_type=>"M"}, {:task_name=>"This is task no 3", :task_type=>"D"}, {:task_name=>"This is task_no_4", :task_type=>"M"}]

Now that we have our attributes properly paired in an array of hashes, we simply iterate over the array and create Tasks:

>> paired_attributes.each { |attributes| Task.create(attributes) }
>> Task.all
#<ActiveRecord::Relation [#<Task id: 1, task_name: "This is task no 1", task_type: "T">, #<Task id: 2, task_name: "This is task no 2", task_type: "M">, #<Task id: 3, task_name: "This is task no 3", task_type: "D">, #<Task id: 4, task_name: "This is task_no_4", task_type: "M">]>
moveson
  • 5,103
  • 1
  • 15
  • 32