【问题标题】:Adding a column to an existing table in a Rails migration在 Rails 迁移中向现有表添加列
【发布时间】:2011-06-17 14:45:34
【问题描述】:

我有一个用户模型,它需要一个 :email 列(我忘记在初始脚手架期间添加该列)。

我打开了迁移文件并添加了t.string :email,添加了rake db:migrate,得到了NoMethodError。然后我添加了这一行

add_column :users, :email, :string

再次rake db:migrate,再次NoMethodError。我在这里错过了一步吗?

编辑:这是迁移文件。

class CreateUsers < ActiveRecord::Migration  
  def self.up  
    add_column :users, :email, :string  
    create_table :users do |t|  
      t.string :username  
      t.string :email  
      t.string :crypted_password  
      t.string :password_salt  
      t.string :persistence_token  

      t.timestamps  
    end  
  end  

  def self.down  
    drop_table :users  
  end  
end

【问题讨论】:

    标签: ruby-on-rails-3


    【解决方案1】:

    如果您已经运行了原始迁移(在编辑之前),那么您需要生成一个新的迁移(rails generate migration add_email_to_users email:string 可以解决问题)。 它将创建一个包含以下行的迁移文件: add_column :users, email, string 然后执行rake db:migrate,它将运行新的迁移,创建新列。

    如果您尚未运行原始迁移,您可以像您尝试做的那样对其进行编辑。您的迁移代码几乎完美:您只需要完全删除 add_column 行(该代码试图在创建表之前向表中添加列,并且您的表创建代码已经更新为包含t.string :email)。

    【讨论】:

    • 为了清楚起见,我们使用复数?所以是add_email_to_users 而不是add_email_to_user
    • 正确。 Rails 中的表名总是复数(以匹配 DB 约定)。
    • 最后一步也可以使用rails db:migrate
    • 是否可以在表格的特定位置创建新列。例如,如果我想在现有“电子邮件”字段之后创建新字段“状态”?
    • @neeraj 你现在可能已经有了答案,但对于其他寻求者来说,是的,你可以在例如t.string :column_x, limit: 10, after: :column_y(至少适用于 Rails 4)
    【解决方案2】:

    在终端上使用这个命令:

    rails generate migration add_fieldname_to_tablename fieldname:string
    

    rake db:migrate
    

    运行此迁移

    【讨论】:

      【解决方案3】:

      有时rails generate migration add_email_to_users email:string 会产生这样的迁移

      class AddEmailToUsers < ActiveRecord::Migration[5.0]
        def change
        end
      end
      

      在这种情况下,您必须手动将add_column 转换为change

      class AddEmailToUsers < ActiveRecord::Migration[5.0]
        def change
          add_column :users, :email, :string
        end
      end
      

      然后运行rake db:migrate

      【讨论】:

      • 1) rails generate migration add_email_to_users email:string 应该在 bundle exec rails c 之后运行还是在终端内运行? 2) 执行查询后生成的文件放在哪里?
      • @sofs1 就在终端中。新文件创建于/db/migrate/
      【解决方案4】:

      你也可以这样做

      rake db:rollback
      

      如果您还没有向表中添加任何数据。然后通过将电子邮件列添加到迁移文件来编辑迁移文件,然后调用

      rake db:migrate
      

      如果您的系统中安装了 rails 3.1 及更高版本,这将起作用。

      更简单的方法是更改​​,让迁移文件中的更改保持原样。 使用

      $rake db:migrate:redo
      

      这将回滚上次迁移并再次迁移。

      【讨论】:

        【解决方案5】:

        要添加一列,我只需按照以下步骤操作:

        1. rails generate migration add_fieldname_to_tablename fieldname:string

          替代方案

          rails generate migration addFieldnameToTablename

          生成迁移后,编辑迁移并定义您希望添加的列具有的所有属性。

          注意:Rails 中的表名总是复数形式(以匹配 DB 约定)。 使用前面提到的步骤之一的示例-

          rails generate migration addEmailToUsers

        2. rake db:migrate

        或者

        1. 您可以从db/schema.rb 更改架构,在SQL 查询中添加您想要的列。
        2. 运行此命令:rake db:schema:load

          警告/注意

          请记住,运行 rake db:schema:load 会自动擦除表中的所有数据。

        【讨论】:

        • 我这样做了,但它没有重做“脚手架”并添加新列。我怎样才能“自动”做到这一点?
        • @John Wooten,您可能想删除 Scaffold 并再次检查它。也删除相应的迁移。
        • 添加注释:更改架构而不更改迁移可能会给维护应用的其他开发人员带来问题。
        【解决方案6】:

        您还可以使用列前或列后将列添加到特定位置,例如:

        rails generate migration add_dob_to_customer dob:date
        

        迁移文件将生成以下代码,但后面除外::email。您需要在: :email 之后或之前添加: :email

        class AddDobToCustomer < ActiveRecord::Migration[5.2]
          def change
            add_column :customers, :dob, :date, after: :email
          end
        end
        

        【讨论】:

        • 为了节省任何浪费时间的人,我(直觉地)之前尝试过: :somecol 但这不起作用(它仍然会添加列,但会将其添加到表格的最右侧)
        • 在 PostgreSQL 中不起作用。见:dba.stackexchange.com/q/3276
        【解决方案7】:

        完成此操作后,我没有摆弄原始迁移,而是创建了一个新迁移,其中只有上部分的添加列和下部分的下拉列。

        如果您向下迁移,您可以更改原始文件并重新运行它,但在这种情况下,我认为这导致迁移无法正常工作。

        正如当前发布的那样,您正在添加列,然后创建表。

        如果您更改顺序,它可能会起作用。或者,当您修改现有迁移时,只需将其添加到创建表中,而不是执行单独的添加列。

        【讨论】:

          【解决方案8】:

          您也可以在迁移中使用特殊的change_table 方法来添加新列:

          change_table(:users) do |t|
            t.column :email, :string
          end
          

          【讨论】:

            【解决方案9】:

            如果您的表已经存在,您也可以使用force: true 强制表中的列。

            示例

            ActiveRecord::Schema.define(version: 20080906171750) do
              create_table "authors", force: true do |t|
                t.string   "name"
                t.datetime "created_at"
                t.datetime "updated_at"
              end
            end
            

            【讨论】:

              【解决方案10】:

              您可以通过

              回滚上次迁移
              rake db:rollback STEP=1
              

              或通过

              回滚此特定迁移
              rake db:migrate:down VERSION=<YYYYMMDDHHMMSS>
              

              并编辑文件,然后再次运行rake db:mirgate

              【讨论】:

                【解决方案11】:

                你也可以这样做.. rails g 迁移 add_column_to_users 电子邮件:字符串

                然后 rake db:migrate 还在您的用户控制器中添加 :email 属性;

                更多详情请查看http://guides.rubyonrails.org/active_record_migrations.html

                【讨论】:

                  猜你喜欢
                  • 2013-05-23
                  • 2021-05-13
                  • 2016-08-02
                  • 2021-11-11
                  • 1970-01-01
                  • 2014-12-26
                  • 1970-01-01
                  • 2015-09-02
                  • 1970-01-01
                  相关资源
                  最近更新 更多