简体   繁体   中英

Possible to generate a Rails migration (model) from hash?

I wonder if there is a method for creating a migration / models from hash.. For example I have a Twitter API response:

 twitter = {:possibly_sensitive_editable=>true,
 :geo=>nil,
 :text=>"http://t.co/asdf",
 :created_at=>"Tue Nov 20 18:10:31 +0000 2012",
 :possibly_sensitive=>false,
 :in_reply_to_status_id_str=>nil,
 :coordinates=>nil,
 :id_str=>"123456",
 :retweeted=>false,
 :in_reply_to_user_id_str=>nil,
 :in_reply_to_screen_name=>nil,
 :source=>"<a href=\"http://twitter.com/download/iphone\" rel=\"nofollow\">Twitter for iPhone</a>",
 :entities=>
 {:media=>
    [{:type=>"photo",
     :indices=>[0,
     20],
     :url=>"http://t.co/asdf",
     :expanded_url=>"http://twitter.com/qwerty/",
     :media_url_https=>"https://p.twimg.com/qwerty.jpg",
     :source_status_id_str=>"123456",
     :id_str=>"123456",
     :sizes=>
           {:medium=>{:h=>1003,
                      :w=>600,
                     :resize=>"fit"}}}]}}

If I want to create a model (or rather models) from this hash, is there a quick way to do it? I can imagine doing it via parsing the whole thing as text and then writing a migration as a text file, but doubt that it is the best way..

So if I want to at least create a model from first level hash (ie just Twitter, not Media) - is there a fast way to achieve that? Is it possible for nested hash?

Is it possible (for non-nested hashes)? Sure. Here you go:

class CreateTweets < ActiveRecord::Migration
  def change
    create_table :tweets do |t|


      twitter = {:possibly_sensitive_editable=>true,
        :geo=>nil,
        :text=>"http://t.co/asdf",
        :created_at=>"Tue Nov 20 18:10:31 +0000 2012",
        :possibly_sensitive=>false,
        :in_reply_to_status_id_str=>nil,
        :coordinates=>nil,
        :id_str=>"123456",
        :retweeted=>false,
        :in_reply_to_user_id_str=>nil,
        :in_reply_to_screen_name=>nil,
        :source=>"<a href=\"http://twitter.com/download/iphone\" rel=\"nofollow\">Twitter for iPhone</a>"
      }

      twitter.keys.each do |key|
        t.string key
      end


      t.timestamps
    end
  end
end

>> Tweet.new
=> #<Tweet id: nil, possibly_sensitive_editable: nil, geo: nil, text: nil, created_at: nil, possibly_sensitive: nil, in_reply_to_status_id_str: nil, coordinates: nil, id_str: nil, retweeted: nil, in_reply_to_user_id_str: nil, in_reply_to_screen_name: nil, source: nil, updated_at: nil>

Is it advisable? no... You can tell that each of these attributes are just strings, not timestamps or booleans.

But you could do this as a baseline and tweak. not recommended

Do you want to create new model classes, and new database tables, based on the names of fields in this response? With some hacking, I'm sure you could. But it would be a bad idea.

Models and database schemas usually are not created at runtime in your application. You don't need to do that. API's usually return data in very structured formats, and it only takes a minute or 2 take to make a migration to hold the data you want, which you then get to use for a very long time.

And it's worth going through each field, thinking about why you want to store it, what data type you want it to be, if you can discard it, etc. Blindly saving every field in this API response to your database will probably end up storing a ton of data that you will never end up using.

Don't be lazy. Create a model, tailor a migration by hand, and think through the data and the code required to manage that model. It's worth the manual effort.

Based on Jesse's suggestion, I extended it to create a sort of (non-rails) / native ruby generator.

My API response contains an array of hashes and my ActiveRecord knowledge is very limited, only just started with Rails, so there's room for improvement here I guess - in the type mapping and structure (eg i might want to iterate through all intances of the hash in the array and put it into a map so i cover variation of fields in different objects).

# Illustrative structure of activities:
# activities = [{"key"=>"val"},{},{}]

puts "class CreateActivities < ActiveRecord::Migration
  def change
    create_table :activities do |t|"
activities.first.each do |key,val|
  arType = case val
    when Hash,Array
      "RELATION-Determine"
    when Float, Fixnum
      "t.integer"
    when FalseClass, TrueClass
      "t.boolean"
    else
      "t.string"
  end
  puts "      #{arType} :#{key}"
end
puts "      t.timestamps null: false
    end
  end
end"

And then run $ ruby activities_generator.rb > db/migrate/$(date +"%Y%m%d%H%M%S")_create_activities.rb (if linux)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM