xaver23
xaver23

Reputation: 1321

How do I add some inserts in rails migration?

After creating a table (by migration), I want to insert some entries directly. How must I write a migration for this?

thanks

Upvotes: 47

Views: 56142

Answers (5)

SMAG
SMAG

Reputation: 788

There are references to using Models in Migrations from trusted sources: The main purpose of Rails' migration feature is to issue commands that modify the schema using a consistent process. Migrations can also be used to add or modify data. This is useful in an existing database that can't be destroyed and recreated, such as a production database.

Seeding should be idempotent as stated in the accepted answer. Meaning that they should be safe to run in Production even if only by accident. Therefore the find_or_create_by method can and should be used in these cases.

We can then leverage the Models in our migrations as follows:

class CreateMyModel < ActiveRecord::Migration[7.0]
  def up
    create_table :my_model do |t|
      # table code here
    end

    MyModel.find_or_create_by(**my_model_attributes)
  end

  def down
    drop_table :my_model
  end
end

As with anything we are doing, especially in production, we should do it with understanding, caution and intent.

An advanced use of this approach can be used to adjust a production DB schema and models to reflect and build new references to newer models over time. This can be done in a single migration using this approach, especially when paired with:

Upvotes: -1

Ryan McGeary
Ryan McGeary

Reputation: 239885

Don't. If you're looking for seed data, you should use db/seeds.rb and rake db:seed instead. More info in this Railscast.

Side note: Always make sure that the code in db/seeds.rb is idempotent. i.e. It should always be safe to re-run your seeds.

But, if you must insert or modify data inside a migration (there are legitimate use-cases for this), it's best to use SQL statements instead. Your model class isn't guaranteed to still be around in the same form in a future version of your application, and running the migrations from scratch in the future might yield errors if you reference the model class directly.

execute "insert into system_settings (name, label, value) values ('notice', 'Use notice?', 1)"

Upvotes: 101

Ju Nogueira
Ju Nogueira

Reputation: 8461

Update: This is the right answer: https://stackoverflow.com/a/2667747/7852


Here's an example from ruby on rails api:

 class AddSystemSettings < ActiveRecord::Migration
    # create the table
    def self.up
      create_table :system_settings do |t|
        t.string  :name
        t.string  :label
        t.text  :value
        t.string  :type
        t.integer  :position
      end

      # populate the table
      SystemSetting.create :name => "notice", :label => "Use notice?", :value => 1
    end

    def self.down
      drop_table :system_settings
    end
  end

Upvotes: 16

David Mayo
David Mayo

Reputation: 69

Edit: PLEASE NOTE - Posters above are correct, you should not populate the DB inside migrations. Don't use this to add new data, only to modify data as part of changing the schema.

For many things, using raw SQL will be preferable, but if you need to insert data as part of a migration (for instance, doing data conversion when breaking out a table into multiple tables), and you want some default AR stuff like convenient DB-independent escaping, you can define a local version of the model class:

class MyMigrationSucksALittle < ActiveRecord::Migration
  class MyModel < ActiveRecord::Base
    # empty guard class, guaranteed to have basic AR behavior
  end

  ### My Migration Stuff Here
  ### ...

end

Note that this works best for simple cases; since the new class is in a different namespace (MyMigrationSucksALittle::MyModel), polymorphic associations declared in the guard model won't work correctly.

A somewhat more detailed overview of available options is located here: http://railsguides.net/2014/01/30/change-data-in-migrations-like-a-boss/

Upvotes: 6

Salil
Salil

Reputation: 47472

create a new migration file like 047_add_rows_in_system_settings.rb

 class AddRowsInAddSystemSettings < ActiveRecord::Migration
        def self.up
          SystemSetting.create{:name => "name1", :label => "Use notice?", :value => 1}
          SystemSetting.create{:name => "name2", :label => "Use notice?", :value => 2}
         end

        def self.down
          SystemSetting.delete_all
        end
      end

OR

while creating table

046_system_settings.rb

class AddSystemSettings < ActiveRecord::Migration
    def self.up
      create_table :system_settings do |t|
        t.string  :name
        t.string  :label
        t.text  :value
        t.string  :type
        t.integer  :position
      end

      SystemSetting.create :name => "notice", :label => "Use notice?", :value => 1
    end

    def self.down
      drop_table :system_settings
    end
  end

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

Upvotes: 3

Related Questions