问题
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