What is the best way to convert all controller params from camelCase to snake_case in Rails?

后端 未结 14 824
灰色年华
灰色年华 2020-12-23 00:02

As you already know, JSON naming convention advocates the use of camelSpace and the Rails advocates the use of snake_case for parameter names.

What is the best way t

相关标签:
14条回答
  • 2020-12-23 00:29

    Another rails 5.1 solution that piggy backs off of the Sebastian Hoitz solution above. To clarify why we need to do this: in R5.1 deep_transform_keys! is no longer a method available to us, since params are no longer inheriting from HashWithIndifferentAccess. And overcomes the issue mentioned by Eliot Sykes where the initializer only works for application/json mime types. It does add overhead to all the requests though. (I'd love to see some initializers for ActionDispatch::Request.parameter_parsers[:multipart_form]) though, since the initializer is a better place to be doing this, 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
    
    0 讨论(0)
  • 2020-12-23 00:32

    you can try this:

    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
    
    0 讨论(0)
  • 2020-12-23 00:33

    Merging Sebastian Hoitz's answer with this gist, I could make it work on rails 4.2, strong parameters AND parameters wrapping with the wrap_parameters tagging method.

    I couldn't make it work using a before_filter, probably because the parameter wrapping is done before filtering.

    In 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
    
    0 讨论(0)
  • 2020-12-23 00:33

    Solution for 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
    
    0 讨论(0)
  • 2020-12-23 00:34

    Example with camelCase to snake_case in rails console

    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>
    

    source:

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

    UPDATE:

    If you have nested attributes and Rails 6 you can do:

    ActionController::Parameters convert to hash and then do deep transform:

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

    Please see:

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

    0 讨论(0)
  • 2020-12-23 00:34

    I wanted to use Chris Healds version, but since I am using Rails 4 I have strong_parameters enabled so I had to change it up a bit.

    This is the version that I came up with:

    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
    
    0 讨论(0)
提交回复
热议问题