How can I move data from one table to another in rails migration?

余生长醉 提交于 2019-12-25 01:18:21

问题


I have set up a rails site with these resources:

users(devise) authors

I have realised that I need to move all authors over to users table because I am setting up roles for these users as an author now.

Currently I have tried the following migration but nothing worked and no data was transferred over to the users table:

class MoveAuthorsColumnDataToUsersTable < ActiveRecord::Migration
  def change
    Author.find_each do |author|
       User.find_or_create_by(
           :username => author.name.downcase.gsub(' ',''),
           :encrypted_password => "",
           :email => "",
           :avatar_file_name => author.avatar_updated_at,
           :avatar_content_type => author.avatar_content_type,
           :avatar_file_size => author.avatar_file_size,
           :avatar_updated_at => author.avatar_updated_at,
           :role_id => "3"
       )
     end
  end
end

I have got an author model setup with attributes in the controller, I am eventually going to transfer all author models relationships to users.

author.rb model:

class Author < ActiveRecord::Base
    has_many :books, dependent: :destroy
    has_many :ideas, dependent: :destroy
    accepts_nested_attributes_for :books
    accepts_nested_attributes_for :ideas
    validates_uniqueness_of :name

    has_attached_file :avatar, :styles => { :large => "980x760", :medium => "300x300>", :thumb => "100x100>" }, :default_url => "/images/:style/missing.png"
    validates_attachment_content_type :avatar, :content_type => /\Aimage\/.*\Z/

end

user.rb model(devise)

class User < ActiveRecord::Base
  belongs_to :role
  def confirmation_required?
    false
  end
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable, :confirmable


  has_attached_file :avatar, styles: {
        large: "600x450#",
        medium: "250x250#",
        small: "100x100#"
    }, :default_url => "/images/:style/filler.png"
  #validates_attachment_content_type :avatar, :content_type => ["image/jpg", "image/jpeg", "image/png", "image/gif"]
  validates_attachment_content_type :avatar, :content_type => /\Aimage\/.*\Z/
  validates :avatar, :email, :username, :password, presence: true

end

Here is the schema for users and authors:

  create_table "authors", force: true do |t|
    t.string   "name"
    t.text     "biography"
    t.datetime "created_at"
    t.datetime "updated_at"
    t.integer  "book_id"
    t.string   "avatar_file_name"
    t.string   "avatar_content_type"
    t.integer  "avatar_file_size"
    t.datetime "avatar_updated_at"
    t.integer  "idea_id"
  end

  create_table "users", force: true do |t|
    t.string   "email",                  default: "", null: false
    t.string   "encrypted_password",     default: "", null: false
    t.string   "reset_password_token"
    t.datetime "reset_password_sent_at"
    t.datetime "remember_created_at"
    t.integer  "sign_in_count",          default: 0,  null: false
    t.datetime "current_sign_in_at"
    t.datetime "last_sign_in_at"
    t.string   "current_sign_in_ip"
    t.string   "last_sign_in_ip"
    t.datetime "created_at"
    t.datetime "updated_at"
    t.string   "avatar_file_name"
    t.string   "avatar_content_type"
    t.integer  "avatar_file_size"
    t.datetime "avatar_updated_at"
    t.string   "username"
    t.string   "confirmation_token"
    t.datetime "confirmed_at"
    t.datetime "confirmation_sent_at"
    t.integer  "role_id"
  end

The end result I am trying to achieve here is to get all authors safely over to users as entries in the postgres database and then from there I can use this data to carry on finishing off what else needs refactoring in the models for users etc.

This will hopefully help someone try and find the right solution to what i am trying to do. I am pretty sure many people have been here before and had the same headache.

Thanks


回答1:


On your user model you have these validations:

  validates :avatar, :email, :username, :password, presence: true

However in your migration you're setting encrypted_password to "" which won't pass the presence true validation on password.

As a side note find_or_create_by is going to do 1 of two things, find the first record that matches your hash (username, etc) or if nothing is found create a new use with that info. If you find the record and don't create it, you'll want to call save after the fact.

I like first_or_initialize so something like:

Author.find_each do |author|
       user = User.first_or_initialize(
           :username => author.name.downcase.gsub(' ',''),
           :encrypted_password => "",
           :email => "",
           :avatar_file_name => author.avatar_updated_at,
           :avatar_content_type => author.avatar_content_type,
           :avatar_file_size => author.avatar_file_size,
           :avatar_updated_at => author.avatar_updated_at,
           :role_id => "3"
       )
       user.save!
     end



回答2:


Assuming: 1.you have created all required column in User table(as it was in author table).

2. You just need to copy all author records to User.

Create your copy_author_to_user.rb file in below location!

# db/scripts/copy_author_to_user.rb
require 'rubygems'

Author.all.each do |a|
  user = User.new(
    :username => a.name.downcase.strip,
    :encrypted_password => '', 
    :email => '',
    :avatar_file_name => a.avatar_updated_at,
    :avatar_content_type => a.avatar_content_type,
    :avatar_file_size => a.avatar_file_size,
    :avatar_updated_at => a.avatar_updated_at,
    :role_id => "3"
  )
  user.save!
end

then from console run : 
$rails runner db/scripts/copy_author_to_user.rb 


来源:https://stackoverflow.com/questions/28089441/how-can-i-move-data-from-one-table-to-another-in-rails-migration

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!