将Rails表从belongs_to迁移到has_and_belongs_to_many

问题描述 投票:0回答:2

目前,我有包含

users
client_id
表(因此,是
User belongs_to :client
)。

我们需要支持与一个用户关联的多个客户端,因此我们实现了一个

User has_and_belongs_to_many :clients
关联。为此,我们:

  • 创建了一个新的
    clients_users
    表,其中包含
    user_id
    client_id
    列;
  • client_id
    中删除了
    users

现在,我们如何为最初在

client_id
表中的每个
users
自动创建 HABTM 记录?我们不想丢失数据。

我不确定从哪里开始,因为

db:migrate
不应该涉及它们之间的模型或关联,并且在我的情况下执行原始查询可能会变得复杂。

ruby-on-rails postgresql database-migration
2个回答
6
投票

只需将新的

has_and_belongs_to_many
关联添加到
User
Client
模型并在迁移后运行。

此解决方案来自 http://manuelvanrijn.nl/blog/2013/03/04/rails-belongs-to-to-has-many/

class MultipleClientsForUser < ActiveRecord::Migration
  def up
    create_table :clients_users, id: false do |t|
      t.references :client, :user
    end

    # define the old belongs_to client associate
    User.class_eval do
      belongs_to :single_client, class_name: "Client", foreign_key: "client_id"
    end

    # add the belongs_to client to the has_and_belongs_to_many client
    User.find_each do |user|
      unless user.single_client.nil?
        user.clients << user.single_client
        user.save
      end
    end

    # remove the old client_id column for the belongs_to associate
    remove_column :users, :client_id
  end

  def down
    add_column :users, :client_id, :integer

    User.class_eval do
      belongs_to :single_client, class_name: "Client", foreign_key: "client_id"
    end

    #Note that only one client may be restored in rollback
    User.find_each do |user|
      user.single_client = user.clients.first unless user.clients.empty?
      user.save
    end

    drop_table :clients_users
  end
end

0
投票

我更喜欢在迁移中使用完全独立的存根模型,因为模型定义将来可能会发生变化。

# change relation between user and customer from belongs_to to has_and_belongs_to_many
class MultipleCustomersForUser < ActiveRecord::Migration[7.0]
  # stub class for conversion of customer to customers
  class User < ActiveRecord::Base
    belongs_to :customer
    has_and_belongs_to_many :customers
  end
  class Customer < ActiveRecord::Base; end

  def up
    create_join_table :users, :customers

    User.find_each do |user|
      user.customers << user.customer if user.customer.present?
      user.save
    end

    remove_reference :users, :customer
  end

  def down
    add_reference :users, :customer

    User.find_each do |user|
      user.customer = user.customers.first
      user.save
    end

    drop_join_table :users, :customers
  end
end
© www.soinside.com 2019 - 2024. All rights reserved.