英文:
Psych errors after Rails version update
问题
我们最近将一个客户的应用程序从Rails 4升级到Rails 5。然而,在运行测试套件后,尝试创建对象时出现了以下问题:
失败/错误:
@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:
尝试加载未指定的类:Policy
其中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
但只是收到以下错误:
失败/错误:require File.expand_path("../../config/environment", __FILE__)
NoMethodError:
未定义方法 `yaml_column_permitted_classes=' for ActiveRecord::Base:Class
您有什么想法可能导致这个问题?本地的Psych版本为psych(默认:3.0.2)
,Rails版本为gem 'rails', '5.2.8'
。
提前感谢!
英文:
We recently updated a client's application from Rails 4 to rails 5.
However, after running the test suite the following issue appeared whilst trying to create an object:
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 is a model in our app/models/
folder.
We tried changing the loading of the YAML to the following:
@service_hash ||= YAML.load_file(
Rails.root.join('config', 'mcp_services.yml'),
permitted_classes: [Policy ],
aliases: true
)[Rails.env]
But it was to no avail.
We also tried changing the application.rb
file to use the following line:
config.active_record.yaml_column_permitted_classes = [
Symbol,
ActiveSupport::HashWithIndifferentAccess,
ActionController::Parameters
but just got the error:
Failure/Error: require File.expand_path("../../config/environment", __FILE__)
NoMethodError:
undefined method `yaml_column_permitted_classes=' for ActiveRecord::Base:Class
Any idea what might be causing this issue?
Local psych is at version psych (default: 3.0.2)
and rails is on gem 'rails', '5.2.8'
Thanks in advance!
答案1
得分: 1
将以下部分翻译为中文:
"Quick unsafe hack is to set this in application.rb..."
"More involved is to add an initializer in config/initializers. The initializer tells rails what classes to allow when loading yaml."
"config/initializers/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"
英文:
Quick unsafe hack is to set this in application.rb...
config.active_record.use_yaml_unsafe_load = true
More involved is to add an initializer in config/initializers. The initializer tells rails what classes to allow when loading yaml.
config/initializers/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
答案2
得分: 0
经过更彻底的调查,发现错误是由于访问 `@response.attributes` 属性引起的,类似于这样:
```ruby
@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,检查所有项的属性。
<details>
<summary>英文:</summary>
After more thorough investigation, it turns out that the error is being caused by accessing the `@response.attributes` property, something similar to this:
```ruby
@ens_response = EnsResponse.create!(response_attributes: @response.attributes)
It was due the fact that the aforementioned property is Hash, that contains several objects, including a property called policy:
that is an object from the same model class (Policy
), hence Psych trying to load an unspecified class caused an error.
The fix was to force-convert this property to a JSON string (since that's the schema row value type required):
@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
)
Moral of the story: Use debuggers such as Pry and check the properties of all items before serialization.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论