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