a.s*_*r.o 32 json ruby-on-rails
如您所知,JSON命名约定主张使用camelSpace,Rails主张使用snake_case作为参数名称.
在rails控制器中将所有请求的参数转换为snake_case的最佳方法是什么?
由此:
{
...
"firstName": "John",
"lastName": "Smith",
"moreInfo":
{
"mealType": 2,
"mealSize": 4,
...
}
}
Run Code Online (Sandbox Code Playgroud)
对此:
{
...
"first_name": "John",
"last_name": "Smith",
"more_info":
{
"meal_type": 2,
"meal_size": 4,
...
}
}
Run Code Online (Sandbox Code Playgroud)
谢谢
Eli*_*kes 58
完成以下步骤后,camelCase通过JSON请求提交的参数名称将更改为snake_case.
例如,命名的JSON请求参数passwordConfirmation将在控制器中被访问params[:password_confirmation]
在config/initializers/json_param_key_transform.rb.创建初始化程序.此文件将仅更改JSON请求的参数解析行为(JSON请求必须具有请求标头Content-Type: application/json).
找到你的Rails版本并选择下面的相应部分(找到你的Rails版本Gemfile.lock):
对于Rails 5,要将camel-case param键转换为snake-case,请将其放在初始化程序中:
# File: config/initializers/json_param_key_transform.rb
# Transform JSON request param keys from JSON-conventional camelCase to
# Rails-conventional snake_case:
ActionDispatch::Request.parameter_parsers[:json] = -> (raw_post) {
# Modified from action_dispatch/http/parameters.rb
data = ActiveSupport::JSON.decode(raw_post)
data = {:_json => data} unless data.is_a?(Hash)
# Transform camelCase param keys to snake_case:
data.deep_transform_keys!(&:underscore)
}
Run Code Online (Sandbox Code Playgroud)
对于Rails 4.2(可能是早期版本),要将camel-case param键转换为snake-case,请将其放在初始化程序中:
# File: config/initializers/json_param_key_transform.rb
# Transform JSON request param keys from JSON-conventional camelCase to
# Rails-conventional snake_case:
Rails.application.config.middleware.swap(
::ActionDispatch::ParamsParser, ::ActionDispatch::ParamsParser,
::Mime::JSON => Proc.new { |raw_post|
# Borrowed from action_dispatch/middleware/params_parser.rb except for
# data.deep_transform_keys!(&:underscore) :
data = ::ActiveSupport::JSON.decode(raw_post)
data = {:_json => data} unless data.is_a?(::Hash)
data = ::ActionDispatch::Request::Utils.deep_munge(data)
# Transform camelCase param keys to snake_case:
data.deep_transform_keys!(&:underscore)
data.with_indifferent_access
}
)
Run Code Online (Sandbox Code Playgroud)
重启rails server.
Ale*_* K. 10
在Rails 6.1中将被添加deep_transform_keys,ActionController::Parameters因此它使您能够使其变得如此简单:
class ApplicationController < ActionController::Base
before_action :underscore_params!
private
def underscore_params!
params.deep_transform_keys!(&:underscore)
end
end
Run Code Online (Sandbox Code Playgroud)
编辑
目前,您可以按以下方式向后移植:
module DeepTransformKeys
def deep_transform_keys!(&block)
@parameters.deep_transform_keys!(&block)
self
end
end
ActionController::Parameters.include(DeepTransformKeys)
Run Code Online (Sandbox Code Playgroud)
ActiveSupport已经提供了String#snakecase方法.您所要做的就是安装一个过滤器,通过params散列进行深度迭代并替换键key.snakecase.
before_filter :deep_snake_case_params!
def deep_snake_case_params!(val = params)
case val
when Array
val.map {|v| deep_snake_case_params! v }
when Hash
val.keys.each do |k, v = val[k]|
val.delete k
val[k.snakecase] = deep_snake_case_params!(v)
end
val
else
val
end
end
Run Code Online (Sandbox Code Playgroud)
将Sebastian Hoitz的答案与这个要点合并,我可以使它在rails 4.2上工作,使用wrap_parameters标记方法包装强参数和参数.
我无法使用a工作before_filter,可能是因为参数包装是在过滤之前完成的.
在config/initializers/wrap_parameters.rb:
# Convert json parameters, sent from Javascript UI, from camelCase to snake_case.
# This bridges the gap between javascript and ruby naming conventions.
module ActionController
module ParamsNormalizer
extend ActiveSupport::Concern
def process_action(*args)
deep_underscore_params!(request.parameters)
super
end
private
def deep_underscore_params!(val)
case val
when Array
val.map {|v| deep_underscore_params! v }
when Hash
val.keys.each do |k, v = val[k]|
val.delete k
val[k.underscore] = deep_underscore_params!(v)
end
val
else
val
end
end
end
end
# Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array.
ActiveSupport.on_load(:action_controller) do
wrap_parameters format: [:json] if respond_to?(:wrap_parameters)
# Include the above defined concern
include ::ActionController::ParamsNormalizer
end
Run Code Online (Sandbox Code Playgroud)
在rails控制台中使用camelCase到snake_case的示例
2.3.1 :001 > params = ActionController::Parameters.new({"firstName"=>"john", "lastName"=>"doe", "email"=>"john@doe.com"})
=> <ActionController::Parameters {"firstName"=>"john", "lastName"=>"doe", "email"=>"john@doe.com"} permitted: false>
2.3.1 :002 > params.transform_keys(&:underscore)
=> <ActionController::Parameters {"first_name"=>"john", "last_name"=>"doe", "email"=>"john@doe.com"} permitted: false>
Run Code Online (Sandbox Code Playgroud)
资源:
http://api.rubyonrails.org/classes/ActionController/Parameters.html#method-i-transform_keys http://apidock.com/rails/String/underscore
Rails 5 的解决方案
before_action :underscore_params!
def underscore_params!
underscore_hash = -> (hash) do
hash.transform_keys!(&:underscore)
hash.each do |key, value|
if value.is_a?(ActionController::Parameters)
underscore_hash.call(value)
elsif value.is_a?(Array)
value.each do |item|
next unless item.is_a?(ActionController::Parameters)
underscore_hash.call(item)
end
end
end
end
underscore_hash.call(params)
end
Run Code Online (Sandbox Code Playgroud)
我不能在这里直接使用其他建议,但它让我走上了正确的轨道。
在 Rails 5.2 中,使用版本化 API,因此无法为整个应用程序更改它。我创建了这个问题,然后将其包含到我的新 api 版本模块的基本控制器中。
module UnderscoreizeParams
extend ActiveSupport::Concern
def process_action(*args)
request.parameters.deep_transform_keys!(&:underscore)
super
end
end
Run Code Online (Sandbox Code Playgroud)
然后在我的 API V3 BaseController 中
class V3::BaseController
include UnderscoreizeParams
end
Run Code Online (Sandbox Code Playgroud)
请享用。
您可以创建一个在任何控制器调用之前运行的过滤器,并向其应用以下指令:
# transform camel case string into snake case
snake_string = Proc.new {|s| s.gsub(/([a-z])([A-Z])/) {|t| "#{$1}_#{$2.downcase}"}}
# transform all hash keys into snake case
snake_hash = Proc.new do |hash|
hash.inject({}) do |memo, item|
key, value = item
key = case key
when String
snake_string.call(key)
when Symbol
snake_string.call(key.to_s).to_sym
else
key
end
memo[key] = value.instance_of?(Hash) ? snake_hash.call(value) : value
memo
end
end
params = snake_hash.call(params)
Run Code Online (Sandbox Code Playgroud)
您必须考虑到上述过程会给每个 Rails 调用带来很小的开销。
如果只是为了符合惯例,我不认为这是必要的。
| 归档时间: |
|
| 查看次数: |
14177 次 |
| 最近记录: |