4

I used nokogiri to parse a xml document into array of hashes:

helpers/countries.helper

module CountriesHelper

  def parse
    @countries = ['australia', 'canada', 'france']
    @countries.inject([]) do |memo, country|
    File.open("public/#{country}.xml") do |f|
    xml = Nokogiri::XML(f)
    path = "//country/stores/"
      memo << xml.xpath(path).map do |x|
           { 'country' => x.parent['country'],
           'store' => x['store']}
    end
   end
  end

# [{"country"=>"australia", "store"=>"store1"}, {"country"=>"france", "store"=>"store2"}]

How can I save this array of hashes format into my database? Lets say I have two models Country and Store.

pyfl88
  • 1,640
  • 13
  • 25

3 Answers3

3

You can serialize an attribute, which means saving it as a particular type of object.

#in your model
serialize :store_hashes, Array

The field should be a text field in the database. I don't know whether or not that's a good idea in this particular instance - i suspect it isn't. But that's how you save an array of hashes to the database.

http://apidock.com/rails/ActiveRecord/Base/serialize/class

Max Williams
  • 30,785
  • 29
  • 115
  • 186
2

You can store your array of hashes in a text field in your database.

Something like this in your migration file:

create_table "your_table", force: true do |t|
  t.text "your_column_name"
end

Or, if you already have the table in the database and just want to add the new column to the table:

class Migration0001
  def change
    add_column :your_table, :your_column_name, :text
  end
end

Just so you know, if you want to save a Hash object in your database and if you define the column type as :text, then Rails should be able to serialize it properly, and you won't need to use serialize explicitly in your model.

But, in your case, it's an Array of Hash, so it's an Array object that needs to be saved in the database, so you need to serialize the field in your model:

serialize :your_column_name, Array

That way, you can save an Array of Hashes in the database. Hope this helps.

K M Rakibul Islam
  • 31,427
  • 11
  • 79
  • 100
0

Assuming country has many stores. Storing the hash in database would make very little sense (in my opinion). Storing in individual tables would make much more sense and easy for querying.

module CountriesHelper

  def parse
    @countries = ['australia', 'canada', 'france']
    @countries.inject([]) do |memo, country|
    File.open("public/#{country}.xml") do |f|
    xml = Nokogiri::XML(f)
    path = "//country/stores/"
      memo << xml.xpath(path).map do |x|
           { 'country' => x.parent['country'],
           'store' => x['store']}

      country = Country.find_by_name(x.parent['country'])
      if country.nil?
        country = Country.create(name: x.parent['country'])
      end
      country.stores.create(name: x['store'])
    end
   end
  end

Database transactions are meant to be invoked from Model; you can refactor later.

class Country < ActiveRecord::Base
  has_many :stores
end


class Store < ActiveRecord::Base
  belongs_to :country
end
illusionist
  • 7,996
  • 1
  • 46
  • 63