简体   繁体   中英

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

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 (ie 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:

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM