sourcecode

Rails에서 모든 컨트롤러 파라미터를 camelCase에서 snake_case로 변환하는 가장 좋은 방법은 무엇입니까?

copyscript 2023. 3. 25. 11:45
반응형

Rails에서 모든 컨트롤러 파라미터를 camelCase에서 snake_case로 변환하는 가장 좋은 방법은 무엇입니까?

이미 알고 있듯이 JSON 명명 규칙은 camelCase 사용을 지지하고 Rails는 파라미터 이름에 snake_case 사용을 지지합니다.

레일 컨트롤러에서 모든 요청의 매개 변수를 snake_case로 변환하는 가장 좋은 방법은 무엇입니까?

여기서부터:

{
  ...
  "firstName": "John",
  "lastName": "Smith",
  "moreInfo":
  {
    "mealType": 2,
    "mealSize": 4,
    ...
  }
}

다음과 같이 입력합니다.

{
  ...
  "first_name": "John",
  "last_name": "Smith",
  "more_info":
  {
    "meal_type": 2,
    "meal_size": 4,
    ...
  }
}

'다음에 하다'라고 합니다.camelCase된 파라미터 됩니다.snake_case.

를 들어, 파라미터는 "JSON"입니다.passwordConfirmation에서 "Native Knowledge" 로 .params[:password_confirmation]

config/initializers/json_param_key_transform.rb가 필요합니다).Content-Type: application/json를 참조해 주세요.

아래에서합니다(「Rails」의 「해 주세요).Gemfile.lock

레일 5 및 6의 경우

레일 5 및 6의 경우 camel-case 매개 변수를 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] = lambda { |raw_post|
  # Modified from action_dispatch/http/parameters.rb
  data = ActiveSupport::JSON.decode(raw_post)

  # Transform camelCase param keys to snake_case
  if data.is_a?(Array)
    data.map { |item| item.deep_transform_keys!(&:underscore) }
  else
    data.deep_transform_keys!(&:underscore)
  end

  # Return data
  data.is_a?(Hash) ? data : { '_json': data }
}

Rails 4.2(및 이전 버전)의 경우

Rails 4.2(및 이전 버전일 수도 있음)에서는 camel-case 매개 변수를 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
  }
)

모든 Rails 버전에 대한 마지막 단계

rails server.

레일 콘솔에서 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>

출처:

http://api.rubyonrails.org/classes/ActionController/Parameters.html#method-i-transform_keys http://apidock.com/rails/String/underscore

갱신:

중첩된 속성과 레일 6이 있는 경우 다음을 수행할 수 있습니다.

액션 컨트롤러:: 파라미터는 해시로 변환한 후 딥 변환을 수행합니다.

params.permit!.to_h.deep_transform_keys { |key| key.to_s.underscore } params.permit!.to_h.deep_transform_values { |value| value.to_s.underscore }

아래를 참조해 주세요.

http://apidock.com/rails/v6.0.0/Hash/deep_transform_values http://apidock.com/rails/v6.0.0/Hash/deep_transform_keys

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

편집

현시점에서는 다음과 같이 백포트를 할 수 있습니다.

module DeepTransformKeys
  def deep_transform_keys!(&block)
    @parameters.deep_transform_keys!(&block)
    self
  end
end

ActionController::Parameters.include(DeepTransformKeys)

ActiveSupport String #snakecase active active active 。 파라미터 해시를 딥 을 수행하고 를 "", "", "", "", "", "", "", "", ""로 바꾸는 .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

Sebastian Hoitz의 답변과 이 요지를 결합하면, 나는 그것이 레일 4.2, 강력한 파라미터 및 태그 부착 방식으로 포장된 파라미터에서 작동하도록 만들 수 있었다.

'이렇게 하다'를 안요.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

레일용 솔루션 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

다른 제안들을 여기서 직접 사용할 수는 없었지만, 그것이 저를 올바른 방향으로 이끌었습니다.

Rails 5.2에서는 버전화된 API를 사용하기 때문에 전체 애플리케이션에 대해 변경할 수 없습니다.새로운 API 버전 모듈의 기본 컨트롤러에 이 문제를 포함시켰습니다.

module UnderscoreizeParams
  extend ActiveSupport::Concern

  def process_action(*args)
    request.parameters.deep_transform_keys!(&:underscore)
    super
  end
end

내 API V3 Base Controller에 추가

class V3::BaseController
  include UnderscoreizeParams
end

즐거운 시간 되세요.

세바스찬 호이츠입니다.HashWithIndifferentiveAccess는 Deep_transform_keys!는 사용할 수 없는 메서드가 아닙니다.또한 이니셜라이저가 애플리케이션/json MIME 유형에서만 작동하는 Eliot Sykes가 언급한 문제를 해결합니다.그래도 모든 요청에 오버헤드가 추가되긴 합니다. (앞서 사용할 이니셜라이저를 보고 싶습니다.)ActionDispatch::Request.parameter_parsers[:multipart_form]가 이을 수행하는 데 더 ). , , , , , , , , , , , , , , , , , , , , , , , , IMO 를 사용합니다

before_action :normalize_key!

 def normalize_keys!(val = params)
  if val.class == Array
    val.map { |v| normalize_keys! v }
  else
    if val.respond_to?(:keys)
      val.keys.each do |k|
        current_key_value = val[k]
        val.delete k
        val[k.to_s.underscore] = normalize_keys!(current_key_value)
      end
    end
    val
  end
  val
end

Rails API JSON 키를 snake_case에서 camelCase로 변환합니다.변환은 점진적으로 진행해야 합니다.즉, 일부 API는 snake_case와 연동하고 다른 API는 camelCase를 사용하는 것으로 변경됩니다.

델의 솔루션은

  • 메서드 " " "ActionController::Parameters#deep_snakeize
  • 메서드 " " "ApplicationController#snakeize_params
  • 설정하다before_action :snakeize_paramscamelCase 키 camelCase를하여

완전히 작동하는 Rails 앱의 예에서는 vochicong/rails-json-api를 사용해 볼 수 있습니다.

# File: config/initializers/params_snakeizer.rb
# Transform JSON request param keys from JSON-conventional camelCase to
# Rails-conventional snake_case
module ActionController
  # Modified from action_controller/metal/strong_parameters.rb
  class Parameters
    def deep_snakeize!
      @parameters.deep_transform_keys!(&:underscore)
      self
    end
  end
end

# File: app/controllers/application_controller.rb
class ApplicationController < ActionController::API
  protected

    # Snakeize JSON API request params
    def snakeize_params
      params.deep_snakeize!
    end
end

class UsersController < ApplicationController
  before_action :snakeize_params, only: [:create]

  # POST /users
  def create
    @user = User.new(user_params)

    if @user.save
      render :show, status: :created, location: @user
    else
      render json: @user.errors, status: :unprocessable_entity
    end
  end
end

Chris Healds 버전을 사용하고 싶었지만, Rails 4를 사용하고 있기 때문에 strong_parameters가 유효하게 되어 있기 때문에 조금 변경할 필요가 있었습니다.

제가 생각해낸 버전은 다음과 같습니다.

before_filter :deep_underscore_params!


def deep_underscore_params!(val = request.parameters)
  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

    params = val
  else
    val
  end
end

컨트롤러 콜 전에 실행되는 필터를 생성하여 다음 순서를 적용할 수 있습니다.

# 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)

위의 절차는 모든 Rails 호출에 약간의 오버헤드를 초래한다는 점을 고려해야 합니다.

만약 그것이 단지 관례에 맞는 것이라면, 나는 이것이 필요하다고 확신하지 않는다.

레일 3에서는 tlewin의 답변이 통하지 않았습니다. 파라임의 = 운영자가 향후 작업을 무효로 만드는 것 같습니다.매우 이상하다.어쨌든 []= 및 delete 연산자만 사용하므로 다음과 같은 것이 좋습니다.

before_filter :underscore_param_keys
def underscore_param_keys
  snake_hash = ->(hash) {
    # copying the hash for iteration so we are not altering and iterating over the same object
    hash.to_a.each do |key, value|
      hash.delete key
      hash[key.to_s.underscore] = value
      snake_hash.call(value) if value.is_a? Hash
      value.each { |item| snake_hash.call(item) if item.is_a? Hash } if value.is_a? Array
    end
  }
  snake_hash.call(params)
end

다음과 같이 시험해 볼 수 있습니다.

class ApplicationController < ActionController::API
  include ControllerHelper
  before_action :deep_underscore_params!

  def deep_underscore_params!(app_params = params)
    app_params.transform_keys!(&:underscore)
    app_params.each do |key, value|
      deep_underscore_params!(value) if value.instance_of?(ActionController::Parameters)
    end
    app_params.reject! { |k, v| v.blank? }
  end
end

위의 Eliot Sykes의 답변에 따르면, Rails5의 경우 조금 더 잘 할 수 있을 것 같습니다.코드가 바뀔 수 있기 때문에 그 기능을 완전히 덮어쓰는 것은 좋아하지 않습니다.그 대신 함수 구성을 사용하는 것이 좋습니다.

# 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] = (
  # Compose the original parser with a transformation
  ActionDispatch::Request.parameter_parsers[:json] >>
    # Transform camelCase param keys to snake_case
    ->(data) {
      data.deep_transform_keys(&:underscore)
    }
)

언급URL : https://stackoverflow.com/questions/17240106/what-is-the-best-way-to-convert-all-controller-params-from-camelcase-to-snake-ca

반응형