views:

1357

answers:

6

I'm trying to create a migration for a simple table that is just used as an enum. So I want to populate the table immediately with its values. I tried the following:

class CreateUserTypes < ActiveRecord::Migration

def self.up
    create_table :user_types do |t|
      t.column :type, :string
      t.timestamps
    end
  end

  def self.down
    drop_table :user_types
  end

  UserType.create :type => "System administrator"
  UserType.create :type => "Simulation controller"
end

but I get this error:

rake aborted!
An error has occurred, all later migrations canceled:

Could not find table 'user_types'

I was following the Rails wiki and expected it to work.

+1  A: 

Try this

class CreateUserTypes < ActiveRecord::Migration

  def self.up
    create_table :user_types do |t|
      t.string :role
      t.timestamps
    end

    UserType.create :role => "System administrator"
    UserType.create :role => "Simulation controller"
  end

  def self.down
    drop_table :user_types
  end

end

It is the self.up method that runs by default when you call rake db:migrate

Edit: changed column name to 'role' as 'type' is reserved for single table inheritance. (See comments). Apologies to Kyle Boon for ending up with a very similar answer.

DanSingerman
Next question: What do I need to do so rake db:migrate will update the database after making changes to the migrations file. rake doesn't seem to work as well as make does for C.
alamodey
Each migrations file is run sequentially. If you make changes to a migration file, you should rollback to that version and re-run. Alternatively you could write a further migration file which makes the change you need on top of the original.
DanSingerman
This still does not work, possibly because (as someone in this thread said) the 'type' column is reserved.
alamodey
Yes - I think that is exactly it. I will update my code to reflect that.
DanSingerman
A: 

Thanks. But what you suggested doesn't seem to be working. Well, I can't see the strings.

sqlite> select * from user_types; 
1||2009-02-08 12:00:56|2009-02-08 12:00:56 
2||2009-02-08 12:00:57|2009-02-08 12:00:57
alamodey
I have edited the code in my answer. Try that version and I think it should work.
DanSingerman
A: 

HermanD's answer should work. I want to point out though, that you should be careful about using a column named 'type' AFAIK , Rails uses that column name for STI.

Bill
+2  A: 

This is a combination of two answers already given, but this should work for you:

class CreateUserRoles < ActiveRecord::Migration

def self.up
  create_table :user_roles do |t|
    t.string :role
    t.timestamps
  end

  UserRole.create :role => "System administrator"
  UserRole.create :role => "Simulation controller"
end

def self.down
  drop_table :user_roles
end

Rename your class UserType to UserRole (along with the associated test classes, assuming you created all of these using the generators). Rails uses the 'type' column for single table inheritance, and automatically populates the field with a class name when you have models that derive from a base class.

Kyle Boon
Just wondering, why is 't.string' used instead of 't.column'? It's the first time I've seen it in a migration.
alamodey
@alamodey - t.string replaced t.column in rails 2.0.
Kyle Boon
+1  A: 

A bit off topic but worth mentioning: It is considered poor form to instantiate data in migrations because the "official" way to create databases in the production environment is

rake db:schema:load

which of course will not load your data from a migration file. You may want to have a look at one of my favorite plugins for this: Seed_Fu.

With Seed_fu, you create your data fixtures in YAML and then issue a

rake db:seed

When you want to get the data set up.

Scott Miller
A: 
  1. Place the create statements inside self.up
  2. Call UserType.reset_column_information after creating the table and before populating it. The model UserType is loaded before creating the table, so rails has collected information about database structure before the table will exists. You need to reset it so Rails will inspect table attributes again.
  3. Don't use 'type' as an attribute name. Its used for STI.

    class CreateUserTypes < ActiveRecord::Migration

    def self.up
      create_table :user_types do |t|
        t.column :role, :string
        t.timestamps
      end
    
    
      UserType.reset_column_information
    
    
      UserType.create :role => "System administrator"
      UserType.create :role => "Simulation controller"
    
    
    end
    
    
    def self.down
      drop_table :user_types
    end
    

    end