【问题标题】:How can I move data from one table to another in rails migration?如何在 Rails 迁移中将数据从一个表移动到另一个表?
【发布时间】:2015-03-21 06:49:17
【问题描述】:

我已经使用这些资源建立了一个 Rails 站点:

用户(设计) 作者

我意识到我需要将所有作者移动到用户表,因为我现在正在为这些用户设置角色作为作者。

目前我尝试了以下迁移,但没有任何效果,也没有数据传输到用户表:

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

我在控制器中设置了带有属性的作者模型,我最终会将所有作者模型关系转移给用户。

author.rb 模型:

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 模型(设计)

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

这是用户和作者的架构:

  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

我试图在这里实现的最终结果是让所有作者作为 postgres 数据库中的条目安全地交给用户,然后我可以从那里使用这些数据继续完成用户模型中需要重构的其他内容等等

这有望帮助某人尝试找到我正在尝试做的事情的正确解决方案。我敢肯定,很多人以前都来过这里,并且遇到过同样的问题。

谢谢

【问题讨论】:

  • 使用pg_dump -t table_name 获取转储,然后将其恢复到pg_restore -t table_name。这是documentation
  • 但是你有什么问题?

标签: ruby-on-rails ruby postgresql ruby-on-rails-4 devise


【解决方案1】:

假设: 1.您已经在用户表中创建了所有必需的列(就像在作者表中一样)。

2。您只需将所有作者记录复制到用户即可。

在以下位置创建您的 copy_author_to_user.rb 文件!

# 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 

【讨论】:

  • Ajay,这是可行的,但只会将第一作者添加到用户中,因为它一直说“电子邮件”已经存在。我正在创建一个全局变量,我可以在其中将用户名添加到电子邮件地址中,如下所示:@emailu = a.name.downcase.strip; 然后在用户新 :email =&gt; '#{emailu}@email-domain.com' 内部有更好的方法吗?
  • 是的,您可以采用这种方法。无论如何,您的重点只是获得唯一的电子邮件 ID。根据您的示例,您只是将您的姓名转换为电子邮件 ID.. 继续使用.. :) 否则,您可以考虑添加 gem 'faker' 并使用假电子邮件 ID 填充您的电子邮件 ID(电子邮件:Faker::Internet.email ) 希望你觉得上面的输入有用:)
  • 这很有效,直到您突然处理 1000 万条记录。
【解决方案2】:

在您的用户模型上,您有以下验证:

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

但是,在您的迁移中,您将 encrypted_password 设置为 "",这不会通过 password 上的存在真实验证。

作为旁注find_or_create_by 将做两件事中的一件,找到与您的哈希(用户名等)匹配的第一条记录,或者如果没有找到任何内容,则使用该信息创建一个新用途。如果您找到记录但没有创建它,您需要在事后调用 save 。

我喜欢first_or_initialize,比如:

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

【讨论】:

  • 嘿 Anthony 这创建了迁移,但是当我查看用户索引页面时,没有一个作者经过
  • 当你进入 Rails 控制台并执行 User.all 时,你看到了你的期望吗?
  • 我只得到 1 个已填充
猜你喜欢
  • 1970-01-01
  • 2012-04-07
  • 2011-09-02
  • 2022-07-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多