开发者

Adding new field to pre-existing table and modifying previously created data in Rails

开发者 https://www.devze.com 2022-12-17 20:12 出处:网络
So I\'ve a user model and a corresponding table (users) with fields: User_id, username, password etc.

So I've a user model and a corresponding table (users) with fields: User_id, username, password etc.

But then I added invitation_limit to users table. Newly created users have invitation开发者_如何学运维_limit, however the users created before the invitation_token migration was run don't have the invitation_limit field.

How do I update the previously created users to include invitation_token field? Mind you I'm not talking about adding invitation_limit field to users table (i.e. migration), but rather updating already created users.

Thanks,


Seed data shouldn't be put in a migration. Migrations are for creating structure, not adding data, and you'll run into problems if you ever move the database.

You could write a rake task. If you create an instance method called something like "generate_invitation_token", you can then write a rake task like this:

# lib/tasks/invitation_tokens.rake
namespace :seed do
  desc "generate invitation tokens for users that don't have one already"
  task :user_tokens => :environment do
    User.all(:conditions => {:invitation_token => nil}).each do |user|
      user.generate_invitation_token
    end
  end
end

You can then call the rake task from the commandline like this:

rake seed:user_tokens

This is a cleaner way to do it.

UPDATE

I've expanded this answer in a blog post called "Adding Columns and Default Data To Existing Models".


The generally accepted strategy for this, unfortunately, is to add another migration which populates those fields. Of course, you can't use active record (or your migrations might break), so best practice is to do this in pure SQL.


What I understand is that you want to update User records, not to create seed (seed adds data to your database, for example Roles ans so on, which are important to your application). From documentaion:

class AddReceiveNewsletterToUsers < ActiveRecord::Migration
  def self.up
    change_table :users do |t|
      t.boolean :receive_newsletter, :default => false
    end
    User.update_all ["receive_newsletter = ?", true]
  end

  def self.down
    remove_column :users, :receive_newsletter
  end
end

You can also use your models inside migration:

User.all(:conditions => {}).each do |user|
  user.do_sth
  user.save
end

and so on, read about caveats

Edit:
After your comment, this is how I think you should do it in migration;

class AddInvitationLimitToUser < ActiveRecord::Migration
  def selt.up
    change_table :users do |t|
      t.integer :invitation_limit # and add validation to model `validates_presence_of` and so on
    end
    # now update all records already in database, which didn't had value in invitation_limit column
    User.update_all ["invitation_limit = ?", 5]
  end

  def self.down
    remove_column, :users, :invitation_limit
  end
end


You want to use the migration for this. The migration is just ruby code, so you can access all the data that your application has access to. Alter data, add missing data, delete rows, etc.

Some quick tips:

  • Write your up and down migration if possible, if not, raise IrreversibleMigration
  • Test it. :)
  • See: Can Rails Migrations be used to convert data?
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号