Rails版本更新后出现心理错误



我们最近将一个客户端应用程序从Rails 4更新到Rails 5。但是,在运行测试套件之后,在尝试创建对象时出现了以下问题:

Failure/Error:
@ens_response = EnsResponse.create!(
edi_request_body:    @response.edi_request_body,
edi_body:            @response.edi_data,
reject_reason:       @response.attributes.try(:[], :reject_reason).try(:[], :text),
response_attributes: @response.attributes
)

Psych::DisallowedClass:
Tried to load unspecified class: Policy

Where Policy是我们的app/models/文件夹中的一个模型。

我们尝试将YAML的加载更改为以下内容:

@service_hash ||= YAML.load_file(
Rails.root.join('config', 'mcp_services.yml'),
permitted_classes: [Policy ],
aliases: true
)[Rails.env]

但是没有用。

我们还尝试更改application.rb文件以使用以下行:

config.active_record.yaml_column_permitted_classes = [
Symbol,
ActiveSupport::HashWithIndifferentAccess,
ActionController::Parameters

但是刚刚得到错误:

Failure/Error: require File.expand_path("../../config/environment", __FILE__)
NoMethodError:
undefined method `yaml_column_permitted_classes=' for ActiveRecord::Base:Class

你知道是什么导致了这个问题吗?Local psych在psych (default: 3.0.2)版本,rails在gem 'rails', '5.2.8'版本

提前感谢!:)

快速不安全的方法是在application.rb…

config.active_record.use_yaml_unsafe_load = true

更复杂的是在config/initializers中添加一个初始化器。初始化器告诉rails在加载yaml时允许哪些类。

配置初始化/yaml_loader.rb

Psych::ClassLoader::ALLOWED_PSYCH_CLASSES = [Policy,
ActionController::Parameters,
ActiveSupport::HashWithIndifferentAccess,
ActiveSupport::TimeWithZone,
ActiveSupport::TimeZone,
DateTime,
]

module Psych
class ClassLoader
ALLOWED_PSYCH_CLASSES = [] unless defined? ALLOWED_PSYCH_CLASSES
class Restricted < ClassLoader
def initialize classes, symbols
@classes = classes + Psych::ClassLoader::ALLOWED_PSYCH_CLASSES.map(&:to_s)
@symbols = symbols
super()
end
end
end
end

经过更彻底的调查,发现错误是由访问@response.attributes属性引起的,类似于以下内容:

@ens_response = EnsResponse.create!(response_attributes: @response.attributes)

这是由于上述属性是Hash,它包含几个对象,包括一个名为policy:的属性,它是来自同一个模型类(Policy)的对象,因此Psych试图加载一个未指定的类会导致错误。

修复方法是将该属性强制转换为JSON字符串(因为这是所需的模式行值类型):

@ens_response = EnsResponse.create!(
edi_request_body:    @response.edi_request_body,
edi_body:            @response.edi_data,
reject_reason:       @response.attributes.try(:[], :reject_reason).try(:[], :text),
response_attributes: @response.attributes.to_json
)

这个故事的寓意:在序列化之前,使用诸如Pry之类的调试器并检查所有项目的属性。