views:

1265

answers:

4

Hi! I'd like to know which is the preferred way to add records to a database table in a Rails Migration. I've read on Ola Bini's book (Jruby on Rails) that he does something like this:

class CreateProductCategories < ActiveRecord::Migration

  #defines the AR class
  class ProductType < ActiveRecord::Base; end

  def self.up

    #CREATE THE TABLES...

    load_data
  end
  def self.load_data
    #Use AR object to create default data
    ProductType.create(:name => "type")
  end
end

This is nice and clean but for some reason, doesn't work on the lasts versions of rails...

The question is, how do you populate the database with default data (like users or something)?

Thanks!

A: 

your migrations have access to all your models, so you shouldn't be creating a class inside the migration.

I am using the latest rails, and I can confirm that the example you posted definitely OUGHT to work.

However, migrations are a special beast. As long as you are clear, I don't see anything wrong with an ActiveRecord::Base.connection.execute("INSERT INTO product_types (name) VALUES ('type1'), ('type2')"). (The advantage to this is, you can easily generate it by using some kind of GUI or web front-end to populate your starting data, and then doing a "mysqldump -uroot database_name.product_types"). Whatever makes things easiest for the kind of person who's going to be executing your migrations and maintaining the product.

+1  A: 

You could use fixtures for that. It means having a yaml file somewhere with the data you want to insert.

Here is a changeset I committed for this in one of my app:

db/migrate/004_load_profiles.rb

require 'active_record/fixtures'

class LoadProfiles < ActiveRecord::Migration
  def self.up
    down()

    directory = File.join(File.dirname(__FILE__), "init_data")
    Fixtures.create_fixtures(directory, "profiles")
  end

  def self.down
    Profile.delete_all
  end
end

db/migrate/init_data/profiles.yaml

admin:
 name: Admin
  value: 1
normal:
 name: Normal user
  value: 2
Keltia
+6  A: 

The Rails API documentation for migrations shows a simpler way to achieve this.

http://api.rubyonrails.org/classes/ActiveRecord/Migration.html

class CreateProductCategories < ActiveRecord::Migration
  def self.up
    create_table "product_categories" do |t|
      t.string name
      # etc.
    end

    # Now populate the category list with default data

    ProductCategory.create :name => 'Books', ...
    ProductCategory.create :name => 'Games', ... # Etc.

    # The "down" method takes care of the data because it
    # drops the whole table.

  end

  def self.down
    drop_table "product_categories"
  end
end

Tested on Rails 2.3.0, but this should work for many earlier versions too.

Andrew Hodgkinson
+1  A: 

You could also define in your seeds.rb file, for instance:

Grid.create :ref_code => 'one' , :name => 'Grade Única'

and after run:

rake db:seed
Marcio Mangar