Question

I am working on an application that is already deployed to some test and staging systems and various developers workstations. I need to add some additional reference data but i'm not sure how to add it.

Most of the advice says use seed.rb, however my understanding is that this is only run once, when the application is initially deployed. Since we don't want to rebuild the test and staging databases just so that we can add 1 row of reference data, is there another way to add the data?

I'm thinking of using a db migration, is this the correct approach?

Thanks

Was it helpful?

Solution

Structure your seed.rb file to allow ongoing creation and updating of data. You are not limited to running a seed file only once and if you think it's only used for initial deployment you will miss out on the flexibility it can offer in setting reference data.

A seed file is just ruby so you can do things like:

user = User.find_or_initialize_by(email: 'bob@example.com')
user.name = 'Bob'
user.password = 'secret'
user.role = 'manager'
user.save!

This will create new data if it doesn't exist or update the data if it finds some.

If you structure your seed file correctly you can also create and update dependent objects.

I recommend using the bang save to ensure that exceptions are raised in the event that an object cannot be saved. This is the easiest method of debugging the seed.

I use the seedbank gem to provide more structure to my seed data, including setting data per environment, dependent seeds and more.

I don't recommend using migrations for seed data. There is a lack of flexibility (how do you target seed data to just one environment for instance) and no real way to build up a reusable set of data that can be run at any time to refresh a particular environment. You would also have a set of migrations which have no reference to your schema and you would have to create new migrations every time you wanted to generate new or vary current data.

OTHER TIPS

You can use a migration, but that's not the safest option you have. Say, for example, you add a record to a table via a migration, then in the future you change that table's schema. When you'll install the app somewhere, you won't be able to run rake db:migrate.

Seeds are always advisable because rake db:seed can be run on a completely migrated schema.

If it's just for a record, go for the rails console.

It's best to use an idempotent method like this in seed.rb or another task called by seed.rb:

Contact.find_by_email("test@example.com") || Contact.create(email: "test@example.com", phone: "202-291-1970", created_by: "System")
# This saves you an update to the DB if the record already exists.

Or similar to @nmott's:

Contact.find_or_initialize_by_email("test@example.com").update_attributes(phone: "202-291-1970", created_by: "System")
# this performs an update regardless, but it may be useful if you want to reset your data.

or use assign_attributes instead of update_attributes if you want to assign multiple attributes before saving.

I use the seed file to add instances to new or existing tables all the time. My solution is simple. I just comment out all the other seed data in the db/seeds.rb file so that only the new seed data is live code. Then run bin/rake db:seed.

I did something like this in seed.rb

users_list = [
   {id: 1, name: "Diego", age: "25"},
   {id: 2, name: "Elano", age: "27"}
]

while !users_list.empty? do
  begin
    User.create(users_list)
  rescue
    users_list = users_list.drop(1) #removing the first if the id already exist.
  end
end

If a item in the list with the given id already exist it will return a exception, then we remove that item and try it again, until the users_list array is empty.

This way you don't need to search each object before include it, but you will not be able tho update the values already inserted like in @nmott code.

Instead of altering seeds.db, which you probably want to use for seeding new databases, you can create a custom Rake task (RailsCast #66 Custom Rake Tasks).

You can create as many Rake tasks as you want. For instance, lets say you have two servers, one running version 1.0 of your app, the other one running 1.1, and you want to upgrade both to 1.2. Then you can create lib/tasks/1-0-to-1-2.rake and lib/tasks`1-1-to-1-2.rake since you may need different code depending on the version of your app.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top