Topic: Migrations and Fixtures Together

I couldn't find a way to automatically load in fixtures other than the Rake task db:fixtures:load, and even then you need to read a whole lot more to find out how to use that selectively.

After some research, digging through the Rails gems, I found a way to make it happen:

require 'active_record/fixtures'

class CreateMyModel < ActiveRecord::Migration
    def self.up
        begin
            ActiveRecord::Base.transaction do
                create_table :my_models do |t|
                    t.column :name, :string
                    # ...
                end

                Fixtures.create_fixtures("test/fixtures", :my_models)
            end
        rescue
            self.down
            raise
        end
    end

    def self.down
        drop_table : my_models if (MyModel.table_exists?)
    end
end


Full article

Since even the most minor error in the YAML file would cause the migration to fail, I added a rescue section which would back out any changes made so that you can retry the migration without having to manually drop the table.

I'd like to think there was a more refined way of doing this. Any ideas?

Maximum Retro - My technical blog

Re: Migrations and Fixtures Together

I'd say the majority of people using migrations don't want to load in fixture data as part of that migration.  Typically fixtures are used for testing purposes only, or if you want to populate a development database.

Migrations are meant to be an easy way to keep your test/dev/production database in sync.

Ruby Rockstars - Ruby Jobs for all!

Re: Migrations and Fixtures Together

In this case I had a large amount of data that needed to be imported in order for the table to be of any use, for example, a listing of countries and some parameters relating to them.

You can do this as a separate procedure, like writing a script, or reading in a file and calling MyModel.create as required, but this seems to do the job in one line of code.

The only draw-back I can see is that the data is imported directly, so any triggers like before_save are not called.

This isn't something I'd do on any model, just those that are strictly dependent on having data in the system.

Are there other ways to achieve the same effect? For example, if you're intending to import data from a CSV file, like a spreadsheet, into a new table.

Maximum Retro - My technical blog

Re: Migrations and Fixtures Together

I'm sitting here wondering the same thing. A very simplified description of my situation is that I have 2 models, question and category:

  def self.up
    create_table :categories do |t|
      t.column :description,         :string,  :null => false
    end
  end

  def self.up
    create_table :questions do |t|
      t.column :question,            :string,  :null => false
      t.column :category_id,         :integer, :null => false
    end
  end

A category has_many questions. So I created a data migration that creates a category and then creates a list of questions for that category using category.id. That repeats for several categories. This is all core data required for deployment.

  def self.up
    cat = Category.create(:description => 'obnoxious')
    cat.save!
    question = Question.create(:question => 'exactly who do you think you are', cat.id)
    question.save!

My problem is that rake db:test:prepare doesn't transfer that data to the test database. So I'll have it for development and production but not test. I'm trying to stay DRY and have meaningful test data. So I don't want to write separate fixtures.

AWDWR creates a separate folder for data fixtures to be loaded by migrations but this won't automatically go into the test db either.

I might have answered my own question. I think I'll create special fixtures for all the core data. I know I can load these into a migration. I'll try to avoid putting them in the /test/fixtures folder but I'm not sure if the fixtures statement in the test code will allow that. If not, maybe I'll use 'core' in their name to distinguish them. And my fixtures will have to look up category_ids based on the description string, so I'll define my description strings in environment.rb.

I think that should do it. The fixtures can be changed independently of the migrations- a potential headache that can be avoided through source control, but something to watch out for. If there's any interest then I'll post my results. Or maybe this has been answered better somewhere else?