【问题标题】:Rails - Add relationship automatically on modelRails - 在模型上自动添加关系
【发布时间】:2019-11-22 16:30:09
【问题描述】:

我有两个模型:

class RecordProduct < ApplicationRecord
end

class ShopiTagProduct < ApplicationRecord
end

我想在模型之间创建多对多关系。我执行这个命令:

rails g migration CreateJoinTableRecordProductsShopyTagProducts record_products:references:index shopi_tag_products:references:index

此命令创建此迁移:

class CreateJoinTableRecordProductsShopyTagProducts < ActiveRecord::Migration[5.2]
    def change
        create_join_table :record_products, :shopi_tag_products do |t|
            t.references :record_products, foreign_key: true, index: {name: :productId}
            t.references :shopi_tag_products, foreign_key: true, index: {name: :tagId}
        end
    end
end

执行 rake db:migrate 时抛出错误:表 'name_new_table' 上的 'name_index_tooooo_long' 太长;限制为 64 个字符。

所以,我将迁移类更改为:

class CreateJoinTableRecordProductsShopyTagProducts < ActiveRecord::Migration[5.2]
    def change
        create_join_table :record_products, :shopi_tag_products do |t|
            t.references :record_products, foreign_key: true, index: {name: :productId}
            t.references :shopi_tag_products, foreign_key: true, index: {name: :tagId}
        end
    end
end

当我执行 rake db:migrate 它创建表,但列是重复的:

record_product_id
shopi_tag_product_id
record_products_id
shopi_tag_products_id

我有两个问题。

第一:为什么列是重复的?正确生成列的正确方法是什么?

第二:我应该在模型中手动添加关系(has_and_belongs_to_many)还是自动添加?

【问题讨论】:

    标签: ruby-on-rails ruby rake dbmigrate


    【解决方案1】:

    我不确定在您的情况下是否可以将has_many 自动添加到模型中,在这种情况下我手动添加它。

    运行 rails g migration CreateJoinTableRecordProductsShopyTagProducts record_products:references:index shopi_tag_products:references:index 将生成此迁移:

    class CreateJoinTableRecordProductsShopyTagProducts < ActiveRecord::Migration[5.2]
      def change
        create_join_table :record_products, :shopi_tag_products do |t|
          t.references :record_products, foreign_key: true
          t.references :shopi_tag_products, foreign_key: true
        end
      end
    end
    

    t.references 在这里是多余的,因为您已经使用了create_join_table

    rails g migration CreateJoinTableRecordProductsShopyTagProducts record_products shopi_tag_products 将完成这项工作。 它会生成这样的文件:

    class CreateJoinTableRecordProductsShopyTagProducts < ActiveRecord::Migration[5.2]
      def change
        create_join_table :record_products, :shopi_tag_products do |t|
          # t.index [:record_product_id, :shopi_tag_product_id]
          # t.index [:shopi_tag_product_id, :record_product_id]
        end
      end
    end
    

    您需要取消注释索引并为其分配名称以解决索引名称过长的问题。

    作为替代方案,您可以这样: rails g model record_products_shopi_tag_products record_product:references shopi_tag_product:references 它将生成:

    class CreateRecordProductsShopiTagProducts < ActiveRecord::Migration[5.2]
      def change
        create_table :record_products_shopi_tag_products do |t|
          t.references :record_product, foreign_key: true
          t.references :shopi_tag_product, foreign_key: true
    
          t.timestamps
        end
      end
    end
    

    注意这里用create_table代替create_join_table,所以在这种情况下你必须写t.references。 在此迁移中,您必须添加 , index: {name: ...} 以解决长索引问题。

    我写过这样的模型:
    rails g model RecordProduct name:string
    rails g model ShopiTagProduct name:string

    record_product.rb

    class RecordProduct < ApplicationRecord
      # has_and_belongs_to_many :shopi_tag_products
    
      # not needed if you use has_and_belongs_to_many
      has_many :record_products_shopi_tag_products, dependent: :destroy
      has_many :shopi_tag_products, through: :record_products_shopi_tag_products
    
      validates :name, presence: true
    end
    

    shopi_tag_product.rb

    class ShopiTagProduct < ApplicationRecord
      # has_and_belongs_to_many :record_products
    
      # not needed if you use has_and_belongs_to_many
      has_many :record_products_shopi_tag_products, dependent: :destroy
      has_many :record_products, through: :record_products_shopi_tag_products
    
      validates :name, presence: true
    end
    

    record_products_shopi_tag_product.rb(如果您使用 has_and_belongs_to_many,则不需要)

    class RecordProductsShopiTagProduct < ApplicationRecord
      belongs_to :record_product
      belongs_to :shopi_tag_product
    end
    

    种子.rb

    RecordProduct.destroy_all
    ShopiTagProduct.destroy_all
    
    r = RecordProduct.create!(name: 'foo')
    s = ShopiTagProduct.create!(name: 'bar')
    
    r.shopi_tag_products << s
    r.save!
    
    p ActiveRecord::Base.connection.execute('select * from record_products_shopi_tag_products')
    
    $ rake db:seed
    [{"record_product_id"=>4, "shopi_tag_product_id"=>4}]
    

    我强烈建议使用has_many through 而不是has_and_belongs_to_many,因为has_and_belongs_to_many 不支持dependent: destroy (habtm relationship does not support :dependent option)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-08-27
      • 2021-09-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多