12

我们在两个模型之间有一个简单的 has_and_belongs_to_many 关系。我们想在该模型中添加一些参数,因此我们需要将其更改为 has_many :through 类型的模型。

据我所知,我们需要添加一个 id 列(以及我们想要的任何列)。但是,我并不清楚 100% 如何做到这一点。如果我们添加一个整数列 :id,rails 会知道那是 'id' 主键吗?

我们使用的是最新的 3.x。

4

4 回答 4

15

假设您的数据库表为由 rails 创建的许多 has_and_belong_to 是patients_physicians

您需要做的就是生成这样的模型

rails g model patients_physician --skip-migration

然后您可以使用迁移命令添加所需的任何列,例如 do

rails g migration add_new_column_to_patients_physician new_column

并且您的数据仍然完好无损,您可以根据您生成的模型进行查询。

不要忘记添加

belongs_to :model_1
belongs_to :model_2 

到新添加的模型 patients_physician

那么您将可以在您需要的模型中进行操作。

has_many patients_physician
has_many :model_2, through: :patients_physician
于 2015-02-20T11:57:55.590 回答
11

只需在迁移时在您的表上添加 id :

add_column :table, :id, :primary_key

这个答案中引用

于 2013-10-17T15:18:59.713 回答
7

这里有一篇文章说明了使用 sql 修补 habtm 表并添加一个 id(作为 pkey):Rails 建模:将 HABTM 转换为 has_many :through。我在使用这种方法时遇到了麻烦,并且可能存在特定于数据库的问题。我最终破坏了连接(habtm)表并创建了一个新的连接模型。那行得通。

一些警告:在这样做之前,我建议在 git 中创建一个分支并将数据库存档,以便在它横向运行时轻松恢复。

这些是步骤:

  1. 编辑两个连接模型以使用 has_many 通过

    class Physician < ActiveRecord::Base
      # has_and_belongs_to_many :patients
      has_many :appointments
      has_many :patients, :through => :appointments
    end
    

    对患者做同样的事情。

  2. 创建新的连接模型:

    rails g model Appointment physician_id:integer patient_id:integer has_insurance:boolean
    

    编辑上面生成的新迁移文件...请注意,“更改”作为迁移方法不起作用,因为我们正在处理数据。见下文。

  3. 在数据库中创建新的连接模型,并通过记录将所有旧的 habtm 关联映射到新的 has_many:

    def self.up
      create_table :appointments do |t|
        t.integer :physician_id
        t.integer :patient_id
        t.boolean :has_insurance
    
        t.timestamps
      end
    
      Physician.find_each {|doc|
        doc.patients.each do |pat|
          Appointment.create!(:physician_id => doc.id, :patient_id => pat.id, :has_insurance => false )
        end
      }
    
      # finally, dump the old hatbm associations
      drop_table :patients_physicians
    
    end
    
  4. 如果按照 Rails 指南重建旧的 habtm 关联似乎太痛苦了,那就中止。但是请注意,使用这种方法无法再回滚迁移。

    def self.down
      raise ActiveRecord::IrreversibleMigration
    end
    

    相反,要“关闭”,只需终止 git 分支,然后重新加载备份数据库。然后,如有必要,您可以从那里恢复 db:rollback。另一方面,如果 has_many through 记录不需要修改,另一种方法是删除 :id 列,并重命名 db:

    def self.down
      remove_column :appointments, :id
      rename_table :appointments, :patients_physicians
    end
    

    我没有测试后者(因为在我的情况下我必须弄乱元数据)。这些想法来自这篇文章:http: //7fff.com/2007/10/31/activerecord-migrating-habtm-to-model-table-suitable-for-has_many-through/

于 2013-06-14T20:35:27.520 回答
6

这是我用于转换团队和用户之间的 has_and_belongs_to_many 关系的迁移:

class CreateTeamMembers < ActiveRecord::Migration
  def up
    # Create a new table with id and timestamps to replace the old one
    create_table :team_members do |t|
      t.belongs_to :team
      t.belongs_to :user
      t.timestamps
    end

    # Now populate it with a SQL one-liner!
    execute "insert into team_members(team_id,user_id) select team_id,user_id from teams_users"

    # drop the old table
    drop_table :teams_users
  end

  def down
    # This leaves the id and timestamps fields intact
    rename_table :team_members, :teams_users
  end
end
于 2015-03-15T23:59:46.683 回答