在一个事务中将嵌套数据持久化到数据库

时间:2019-01-19 16:46:24

标签: ruby-on-rails ruby activerecord has-many

我有3种型号:

class Address < ApplicationRecord
    has_one :company_address
end
class CompanyAddress < ApplicationRecord
    belongs_to :address, dependent: :destroy
    belongs_to :address_type
end
class Company < ApplicationRecord
  has_many :company_addresses
end

我正在从另一个应用程序获取JSON数据。

数据由公司属性和一个/一个或多个company_address组成,每个公司地址仅包含一个地址

我希望能够自动插入和更新数据,如果发生任何故障,我想充当迁移的角色

当我在require上设置strong_params时,我没有收到company_addresses数组,但是当我只使用permit时,效果很好

这不起作用:

params.require(:company)
          .permit([
          :short, :name, :company_legal_form_id,
          :company_role_id, :parent_id, :email,
          :fax, :phone, :description,
          :comment, :changed_by,
          company_addresses: [
              :company_id, :address_type_id, :addition,
              :comment, :changed_by,
              address: [
                  :street, :zip, :city,
                  :country_id, :other1, :other2,
                  :other3, :comment, :changed_by
              ]
          ]
      ])

这有效:

params.permit([
          :short, :name, :company_legal_form_id,
          :company_role_id, :parent_id, :email,
          :fax, :phone, :description,
          :comment, :changed_by,
          company_addresses: [
              :company_id, :address_type_id, :addition,
              :comment, :changed_by,
              address: [
                  :street, :zip, :city,
                  :country_id, :other1, :other2,
                  :other3, :comment, :changed_by
              ]
          ]
      ])

因此,我使用这些方法创建了一个名为CompanyForm的表单对象。

class CompanyForm
  include ActiveModel::Model

  attr_accessor(
      :company_attributes
  )

  def save
    @company_id = company_attributes.delete('id')

    company_addresses_attributes = company_attributes.delete('company_addresses')

    company_attributes[:changed_by] = 'user'
    company.update!(p company_attributes)
    @company_id = company.id

    if company_addresses_attributes.empty?
      company.company_addresses.destroy_all
    end

    company_addresses_attributes.each do |company_address_attributes|
      @company_address_id = find_company_address_id(company_address_attributes)

      address_attributes = company_address_attributes.delete('address')
      @address_id = find_address_id(address_attributes)

      address_attributes[:changed_by] = 'user'
      address.assign_attributes(p address_attributes)
      @address_id = address.id

      company_address[:changed_by] = 'user'
      company_address.build_address(@address.attributes)
      company_address.assign_attributes(p company_address_attributes)

      company.company_addresses.update!(p company_address.attributes)
    end
  end

  private
    def company
      @company ||= Company.find_by(id: @company_id) || Company.new()
    end

    def address
      @address ||= Address.find_by(id: @address_id) || Address.new()
    end

    def company_address
      @company_address ||= CompanyAddress.find_by(id: @company_address_id) || CompanyAddress.new()
    end

    def find_company_id(params)
      params.dig(:id)
    end

    def find_company_address_id(params)
      params.dig(:id)
    end

    def find_address_id(params)
      params.dig(:id)
    end
end

第一个问题是:为什么在:company上设置require时为什么也不能得到company_address

第二个问题是,如何使我的代码正常工作?我知道代码确实很丑陋,但是我对Rails和Ruby还是陌生的。

1 个答案:

答案 0 :(得分:0)

这似乎是JSON本身的问题-如果您提供了在该请求中发送的JSON的实际示例,则可能会有所帮助。结构可能与您预期的不同(例如,“公司”嵌套在另一个键中)。 尝试在处理请求的控制器的第一行使用binding.pry,并调查paramsparams.require(:company)的返回值,这可能会带您答案。