使用嵌套的has_many关联在模型中创建数据库条目时出错

时间:2018-03-19 22:09:23

标签: ruby-on-rails ruby-on-rails-5.1

设定:

可以为预订分配多个资源。预留资源组合可以有多个SetUps。

我尝试设置这样的模型:

yarn server
yarn run v1.5.1
$ lerna exec --scope @amplifactory/server -- nodemon --exec "babel-node start-server.js
lerna info version 2.9.0
lerna info scope @amplifactory/server
[nodemon] 1.17.2
[nodemon] to restart at any time, enter `rs`
[nodemon] watching: *.*
[nodemon] starting `babel-node start-server.js`
D:\monorepo\node_modules\babel-core\lib\transformation\file\options\option-manager.js:328
        throw e;
        ^

Error: Couldn't find preset "@babel/es2017" relative to directory "D:\\9. DEV\\WORKSPACE\\amplifactory\\packages\\server"
    at D:\monorepo\node_modules\babel-core\lib\transformation\file\options\option-manager.js:293:19
    at Array.map (native)
    at OptionManager.resolvePresets (D:\monorepo\node_modules\babel-core\lib\transformation\file\options\option-manager.js:275:20)
    at OptionManager.mergePresets (D:\monorepo\node_modules\babel-core\lib\transformation\file\options\option-manager.js:264:10)
    at OptionManager.mergeOptions (D:\monorepo\node_modules\babel-core\lib\transformation\file\options\option-manager.js:249:14)
    at OptionManager.init (D:\monorepo\node_modules\babel-core\lib\transformation\file\options\option-manager.js:368:12)
    at compile (D:\monorepo\node_modules\babel-register\lib\node.js:103:45)
    at loader (D:\monorepo\node_modules\babel-register\lib\node.js:144:14)
    at Object.require.extensions.(anonymous function) [as .js] (D:\monorepo\node_modules\babel-register\lib\node.js:154:7)
    at Module.load (module.js:487:32)
[nodemon] app crashed - waiting for file changes before starting...

步骤:

  1. 创建预订,分配资源,有效:

    class SetUp < ApplicationRecord
      has_many :reservation_resource_set_ups, dependent: :destroy
      has_many :reservations, through: :reservation_resource_set_ups
      has_many :resources, through: :reservation_resource_set_ups
    end
    
    class Resource < ApplicationRecord
      has_many :reservation_resources, dependent: :destroy
      has_many :reservation_resource_set_ups, dependent: :destroy
      has_many :reservations, through: :reservation_resources
      has_many :set_ups, through: :reservation_resource_set_ups
    end
    
    class Reservation < ApplicationRecord
      has_many :reservation_resources, dependent: :destroy
      has_many :reservation_resource_set_ups, dependent: :destroy
      has_many :resources, through: :reservation_resources
      has_many :set_ups, through: :reservation_resource_set_ups
    end
    
    class ReservationResource < ApplicationRecord
      belongs_to :reservation
      belongs_to :resource
      has_many :reservation_resource_set_ups
      has_many :set_ups, through: :reservation_resource_set_ups
    end
    
    class ReservationResourceSetUp < ApplicationRecord
      belongs_to :reservation
      belongs_to :resource
      belongs_to :set_up
    end
    

    reservation和reservation_resources表格已正确更新。

  2. 将设置分配给reservation_resource,失败:

    res1 = Reservation.create(name:"res name")
    res1.resources << Resource.find(1)  # resource with id = 1 exists
    

    此操作失败,错误为res1.resources.first.set_ups << SetUp.find(1) # set_ups with id = 1 exists

  3. 你能指点我正确的方向吗?谢谢!

    (这是架构,如果有用......)

    ActiveRecord::RecordInvalid (Validation failed: Reservation must exist)

2 个答案:

答案 0 :(得分:1)

&LT;&LT;当您需要设置多个外键时,方法无用。

集合&lt;&lt;方法通过将其外键设置为调用模型的主键,将一个或多个对象添加到集合中。

所以你要对待代码

res1.resources.first.set_ups << SetUp.find(1) # set_ups with id = 1 exists

作为

ReservationResourceSetUp.create(
  set_up: SetUp.find(1), # from << SetUp.find(1)
  resource: res1.resources.first, # from left side
  reservation: nil # raises the error
)

要创建条目,只需指定所有键:

ReservationResourceSetUp.create(
  set_up: SetUp.find(1),
  resource: res1.resources.first,
  reservation: res1
)  

答案 1 :(得分:1)

您的模型存在一些问题。例如:

  • ReservationResource has_many :reservation_resource_set_ups。 ActiveRecord假定ReservationResourceSetUp中的reservation_resource_id

但是

  • ReservationResourceSetUp不belongs_to :reservation_resource

我建议您对模型进行一些更改:

class Resource < ApplicationRecord
  has_many :reservation_resources, dependent: :destroy
  has_many :reservations, through: :reservation_resources
  has_many :reservation_resource_set_ups, through: :reservation_resources
  has_many :set_ups, through: :reservation_resource_set_ups
end

class Reservation < ApplicationRecord
  has_many :reservation_resources, dependent: :destroy
  has_many :resources, through: :reservation_resources
  has_many :reservation_resource_set_ups, through: :reservation_resources
  has_many :set_ups, through: :reservation_resource_set_ups
end

class ReservationResource < ApplicationRecord
  belongs_to :reservation
  belongs_to :resource
  has_many :reservation_resource_set_ups
  has_many :set_ups, through: :reservation_resource_set_ups
end

class SetUp < ApplicationRecord
  has_many :reservation_resource_set_ups, dependent: :destroy
  has_many :reservations_resources, through: :reservation_resource_set_ups
  has_many :resources, through: :reservation_resources
  has_many :reservations, through: :reservation_resources
end

class ReservationResourceSetUp < ApplicationRecord
  belongs_to :reservation_resource
  belongs_to :set_up
end

主要的变化是ReservationResourceSetUp现在属于ReservationResource和SetUp(而不是Reservation,Resource和SetUp)。在实践中它是一样的,但我认为它以更好的方式处理你的情况。首先为资源创建预留。然后为此ReservationResource分配一个或多个SetUps。我认为如果您进行这些更改,您的代码将会起作用。您当然必须更改迁移。现在您的ReservationResourceSetUp将有一个reservation_resource_id和一个set_up_id。