#1
  1. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Sep 2010
    Posts
    6
    Rep Power
    0

    Rails - Iterating through nested arrays


    Hi I'm very new to rails and need some help on iterating through nested arrays. I'm trying to figure out how to do mass-inserts for each values that is different between the make, model and color of cars.

    The params that are pass are:

    "make" => ["Honda", "Honda"],
    "model" => ["Civic", "Accord"],
    "color" => [{"Black", "White", "Red"}, {"Black", "White"}]

    So with these params passed, I wanted to have 5 inserts to occur.

    1. Civic - Black
    2. Civic - White
    3. Civic - Red
    4. Accord - Black
    5. Accord - White


    Here what I've got so far that pushes the insert query that builds it. But I'm unsure how to make it insert 5 times according to what I've listed above:

    Code:
    def self.cars(make, model, color)
      inserts = []
        color.each do |i|
          inserts.push "('#{make}', '#{model}', '#{i}')"
         end
    
      Foo.connection.execute "INSERT INTO car_inventory (make, model, color) VALUES #{inserts.join(", ")}"
    end
    Please help.
  2. #2
  3. No Profile Picture
    Contributing User
    Devshed Novice (500 - 999 posts)

    Join Date
    Jan 2004
    Location
    Constant Limbo
    Posts
    989
    Rep Power
    363
    Arrays have a method called each_with_index which is what it looks like you want. Consider the following:
    Code:
    irb(main):001:0> make = ["honda", "honda"]
    => ["honda", "honda"]
    irb(main):002:0> model = ["civic", "accord"]
    => ["civic", "accord"]
    irb(main):003:0> color = [["black", "white", "red"], ["black", "white"]]
    => [["black", "white", "red"], ["black", "white"]]
    irb(main):004:0> make.uniq.each do |mk|
    irb(main):005:1*    model.each_with_index do |mdl, idx|
    irb(main):006:2*       color[idx].each do |col|
    irb(main):007:3*          puts "#{mk}:#{mdl}:#{col}"
    irb(main):008:3>       end
    irb(main):009:2>    end
    irb(main):010:1> end
    honda:civic:black
    honda:civic:white
    honda:civic:red
    honda:accord:black
    honda:accord:white
    True happiness is not getting what you want, it's wanting what you've already got.

    My Blog
  4. #3
  5. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Sep 2010
    Posts
    6
    Rep Power
    0
    L7Sqr, Thanks for the reply, which helps me understand this better. But let's say my form (using form_for) has 3 checkboxes for Black, White, and Red. With all the colors checked, the values are loaded into mass-assignment called 'car' as shown below:

    Code:
    "car"=>{"make"=>"Honda", "color"=>["0", "Black", "0", "White", "0", "Red"], "model"=>"Accord", "tinted"=>"yes"}}
    (Not sure why the check_box helper puts '0' along with the values but I'm sure I can place a conditional to work around that.)

    So with that mass-assignment, is it possible to put some code in the model that iterates through each color and does 3 inserts?
  6. #4
  7. No Profile Picture
    Contributing User
    Devshed Novice (500 - 999 posts)

    Join Date
    Jan 2004
    Location
    Constant Limbo
    Posts
    989
    Rep Power
    363
    Code:
    irb(main):001:0> hash = {}
    => {}
    irb(main):002:0> hash["car"] = {"make"=>"Honda", "color"=>["0", "Black", "0", "White", "0", "Red"], "model"=>"Accord", "tinted"=>"yes"}
    => {"model"=>"Accord", "tinted"=>"yes", "color"=>["0", "Black", "0", "White", "0", "Red"], "make"=>"Honda"}
    irb(main):003:0> car = hash["car"]
    => {"model"=>"Accord", "tinted"=>"yes", "color"=>["0", "Black", "0", "White", "0", "Red"], "make"=>"Honda"}
    irb(main):004:0> make = car["make"]
    => "Honda"
    irb(main):005:0> model = car["model"]
    => "Accord"
    irb(main):006:0> colors = car["color"]
    => ["0", "Black", "0", "White", "0", "Red"]
    irb(main):007:0> [1,3,5].each do |i|
    irb(main):008:1*    puts "(#{make}, #{model}, #{colors[i]})"
    irb(main):009:1> end
    (Honda, Accord, Black)
    (Honda, Accord, White)
    (Honda, Accord, Red)
    => [1, 3, 5]
    irb(main):010:0>
    What you'd like to do is convert the color array into a hash but the order of the elements prevents that directly due to multiple assignments to the same key. For instance
    Code:
    irb(main):001:0> colors = ["0", "Black", "0", "White", "0", "Red"]
    => ["0", "Black", "0", "White", "0", "Red"]
    irb(main):002:0> Hash[*colors]
    => {"0"=>"Red"}
    irb(main):003:0> colors = ["Black", "0", "White", "0", "Red", "0"]
    => ["Black", "0", "White", "0", "Red", "0"]
    irb(main):004:0> Hash[*colors]
    => {"Black"=>"0", "Red"=>"0", "White"=>"0"}
    irb(main):005:0>
    Which is why I used the array of 1, 3, 5 to index the color values. This is brittle and as you add colors this will break. The best way to do that is to convert the color array to an appropriate structure and iterate through that directly.
    True happiness is not getting what you want, it's wanting what you've already got.

    My Blog
  8. #5
  9. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Sep 2010
    Posts
    6
    Rep Power
    0
    Originally Posted by L7Sqr
    Code:
    irb(main):001:0> hash = {}
    => {}
    irb(main):002:0> hash["car"] = {"make"=>"Honda", "color"=>["0", "Black", "0", "White", "0", "Red"], "model"=>"Accord", "tinted"=>"yes"}
    => {"model"=>"Accord", "tinted"=>"yes", "color"=>["0", "Black", "0", "White", "0", "Red"], "make"=>"Honda"}
    irb(main):003:0> car = hash["car"]
    => {"model"=>"Accord", "tinted"=>"yes", "color"=>["0", "Black", "0", "White", "0", "Red"], "make"=>"Honda"}
    irb(main):004:0> make = car["make"]
    => "Honda"
    irb(main):005:0> model = car["model"]
    => "Accord"
    irb(main):006:0> colors = car["color"]
    => ["0", "Black", "0", "White", "0", "Red"]
    irb(main):007:0> [1,3,5].each do |i|
    irb(main):008:1*    puts "(#{make}, #{model}, #{colors[i]})"
    irb(main):009:1> end
    (Honda, Accord, Black)
    (Honda, Accord, White)
    (Honda, Accord, Red)
    => [1, 3, 5]
    irb(main):010:0>
    What you'd like to do is convert the color array into a hash but the order of the elements prevents that directly due to multiple assignments to the same key. For instance
    Code:
    irb(main):001:0> colors = ["0", "Black", "0", "White", "0", "Red"]
    => ["0", "Black", "0", "White", "0", "Red"]
    irb(main):002:0> Hash[*colors]
    => {"0"=>"Red"}
    irb(main):003:0> colors = ["Black", "0", "White", "0", "Red", "0"]
    => ["Black", "0", "White", "0", "Red", "0"]
    irb(main):004:0> Hash[*colors]
    => {"Black"=>"0", "Red"=>"0", "White"=>"0"}
    irb(main):005:0>
    Which is why I used the array of 1, 3, 5 to index the color values. This is brittle and as you add colors this will break. The best way to do that is to convert the color array to an appropriate structure and iterate through that directly.

    Would you know the Rails way of making this work so that the values are inserted into the db 3 times at once?
  10. #6
  11. No Profile Picture
    Contributing User
    Devshed Novice (500 - 999 posts)

    Join Date
    Jan 2004
    Location
    Constant Limbo
    Posts
    989
    Rep Power
    363
    I would not. Rails is a framework built on top of Ruby and I've neither needed nor bothered to learn it. However, under the interface, you are going to be iterating over an enumeration of values and joining them somehow to make your SQL statements.

    There are people here who have used rails more than myself and maybe they will assist - if not you can start to look at how things are done by digging through the code.
    True happiness is not getting what you want, it's wanting what you've already got.

    My Blog

IMN logo majestic logo threadwatch logo seochat tools logo