all repos — h3rald @ 6ed04d62656d222df819ecfd406a5afb3166d316

The sources of https://h3rald.com

content/articles/simply-on-rails-4-default-data-migrations.textile

 1
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
 119
 120
 121
 122
 123
 124
 125
 126
 127
 128
 129
 130
----- 
permalink: simply-on-rails-4-default-data-migrations
filters_pre: 
- erb
- redcloth
title: "Simply On Rails - Part 4: Quick and Easy Default Data Migrations"
comments: 
- :date: 2007-09-15 23:41:30 +02:00
  :author: Pei Mei
  :url: http://www.railsjitsu.com/
  :id: 76
  :body: "Very nice. I still prefer to include my migrations as rails code User.create() in my migrations to avoid having developers create dodgy yaml files though, especially with pks.\n  "
- :date: 2007-09-16 02:40:46 +02:00
  :author: Fabio Cevasco
  :url: http://www.h3rald.com
  :id: 79
  :body: Indeed, indeed you are right. You have to be careful when you prepare the YAML files, and in certain situation (and for certain kind of data) a more standard approach is recommendable.
- :date: 2007-11-27 16:35:58 +01:00
  :author: Mike
  :url: http://www.floristone.com
  :id: 137
  :body: |-
    Cool code and post. I second the idea of using Migrations with such application.
    
    Thanks
- :date: 2007-12-22 02:47:20 +01:00
  :author: Electrical Repair
  :url: http://www.asaprepair.com/content/Electrical-Repair/
  :id: 171
  :body: |
    Migrations would make the application much more flexible in terms of moving it among different DB servers and more.

date: 2007-09-15 13:10:00 +02:00
tags: 
- rails
- ruby
- databases
type: article
toc: true
-----
In the "last post":http://www.h3rald.com/blog/simply-on-rails-3-shared-controller of this series I tried to find a DRY(Don't Repeat Yourself) solution to deal with tables storing "ancillary" data, i.e. names of user roles, predefined categories, page state names and other similar things.
I personally chose to put this kind of data to make my application more dynamic, although I could have decided to use ENUMs or simply ordinary varchar fields -- that would have been easier, but less flexible. For now, I'm sticking with my original choice.

The data in these tables is kind of a prerequisite for the application to run: I must be able to have a status to assign to a user when creating it, and the same applies to roles. Sure, I could spend 20 minutes populating these tables manually, but it would be nice if there was a less tedious way, wouldn't it?

There is indeed. The inspiration came from a technique described in the book (which I highly recommend) _Agile Web Development With Rails_, in which the author outlines how it would be possible to use Rails' fixtures and migrations to load data in the database automatically from YAML files. 
All you have to do is create a migration to load the specified YAML files and you're all set.

I wanted to take a little step further, allowing the migration to load data from _all YAML files in a specific directory_, automatically.Let's start creating the YAML files then and place them all in one directory of the application like @/db/migrate/defaults@. Here's the one I used for user roles, for example:

<% highlight :yaml do %>
visitor:
	id: 1
	name: Visitor
	level: 0

user:
	id: 2
	name: User
	level: 10

contributor:
	id: 3
	name: Contributor
	level: 20

provider:
	id: 4
	name: Provider
	level: 50

operator:
	id: 5
	name: Operator
	level: 100

administrator:
	id: 6
	name: Administrator
	level: 500

webmaster:
	id: 7
	name: Webmaster
	level: 1000
<% end %>

The important thing to remember is to provide a unique string to identify each record, before specifying each fiels. The other files look similar, so I won't bother listing them here. 

And here's the simple code for the migration:

<% highlight :ruby do %>
require 'active_record/fixtures'

class LoadDefaults < ActiveRecord::Migration

	def self.up
		down
		models = self.default_models
		models.each do |m|   
			Fixtures.create_fixtures(self.default_directory, m)
		end
	end

	def self.down
		models = self.default_models
		models.each do |m|
			eval("#{m.singularize.capitalize}.delete_all")
		end
	end

	def self.default_directory
		File.join(File.dirname(__FILE__), "defaults" )
	end

	def self.default_models
		files, names = Dir.glob("#{self.default_directory}/*.yml"), []
		unless files.blank?
			files.each { |f| names << File.basename(f, '.yml') }
			names
		else
			[]
		end
	end

end
<% end %>

Basically the migration will look in a directory named "defaults" for some YAML files named after a particular database table, and it will attempt to load all the records defined in each one of them. 
The @down@ method of the migration _deletes all the data in the specified tables_, so use with care...