1

jsonapi-serializer在我的 Rails 应用程序中,我通过gem以 JSON API 标准格式将数据发送到反应前端。这对于来自我们数据库的数据很有效,但是当我们有失败的表单数据时,它以 rails 嵌套资源的形式发送,有时需要在实际保存记录之前返回错误的数据。

当新模型数据验证失败时,我需要将这些错误返回到我的前端并保持关联完好无损。我也一直在尝试运行它们jsonapi-serializer,但是没有 id 的记录不会成为relationships密钥。问题是失败的新记录没有id,它们返回到前端未关联。

到目前为止,我对此的唯一解决方案是在其中手动填充假的临时 ID。我不确定我是否遗漏了一些明显的东西。该 id 在前端被删除以重新提交。我的解决方案并不完美,并且存在局限性和问题。

有没有内置的方法可以做到这一点,还是我坚持自己的实现?是否有某种替代键可以用于此关联?

对于它的价值,这是我到目前为止的实现,只是为了澄清我在做什么。它远非完美,很多代码似乎应该是内置解决方案的问题。它基于尝试迭代正在序列化的对象树并查看是否需要“假”ID。这仍然会扼杀一些可以通过的东西,包括:[]

class BaseSerializer
  module ShimIdConcerns
    extend ActiveSupport::Concern
      
    private
  
    # Very Important! Controls relationship of json api assocs in front end
    # The id that is returned to the front end needs to be smarter than simply
    # the actual id or nil. The id is used to associate jsonapi objects to their
    # main resource whether they have an id yet or not. Sometimes these objects 
    # are not persisted, but have errors and need to be associated properly in the UI. 
    # Works in conjuncton with attribute :is_persisted
    def shim_id_on_failing_new_associations(resource, options)
      shim_id_on_failing_new_associations_recursive resource, options[:include].to_a
    end

    # dot_assocs: expects assocs in 'packages.package_services.service' format
    def shim_id_on_failing_new_associations_recursive(resource, dot_assocs)
      assocs = simplify_assocs(dot_assocs)

      assocs.each do |assoc_path|
        next if assoc_path.blank?
        segments = assoc_path.split('.') 
        method = segments.shift
        next unless resource.respond_to?(method)
        assoc = resource.send(method)

        if assoc.is_a?  ActiveRecord::Base
          shim_id(resource) 
          shim_id_on_failing_new_associations_recursive assoc, segments.join('.')
        elsif assoc.is_a?(ActiveRecord::Associations::CollectionProxy) || assoc.is_a?(Array)
          assoc.each do |one_of_many|
            shim_id_on_failing_new_associations_recursive one_of_many, segments.join('.')
          end
        end
      end
    end

    # Gives a temp id on failing or new resources so they can be associated in react
    # in jsonapi/react. Ensure this id is not re-submitted, however
    def shim_id(resource) 
      resource.id = rand(1000000000000) if resource.id.nil? && resource.new_record?
    end

    
    # turns
    #   [ :reservation, :'reservation.client', :'reservation.client.credit_card' ]
    # into
    #   [ "reservation.client.credit_card" ]
    # to avoid duplicate processing
    def simplify_assocs(dot_assocs)
      ap dot_assocs
      all = [dot_assocs].flatten.map(&:to_s)
      simp = []
      
      # yes quadratic, but will be little data
      all.each do |needle|
        matches = 0
        all.each do |hay|
          matches += 1 if hay.index(needle) === 0 
        end
        simp << needle if matches === 1
      end
      simp
    end
  end
end
4

0 回答 0