Make blank params[] nil

前端 未结 13 599
半阙折子戏
半阙折子戏 2020-12-13 18:36

When a user submits a form and leaves certain fields blank, they get saved as blank in the DB. I would like to iterate through the params[:user] collection (for example) an

相关标签:
13条回答
  • 2020-12-13 19:13

    Ordinarily I would encourage functionality to be moved into the model, as stated in other answers this means that you will get the same behavior no matter where the change originates from.

    However, I don't think in this case it is correct. The affect being noticed is purely down to not being able to encode the difference between a blank string and nil value in the HTTP request. For this reason it should be remedied at the controller level. It also means that in other places it is still possible to store an empty string in the model (which there could be for a legitimate reason for, and if not it is simple to cover with standard validations).

    The code I'm using to overcome this problem is:

    # application_controller.rb
    ...
    
    def clean_params
      @clean_params ||= HashWithIndifferentAccess.new.merge blank_to_nil( params )
    end
    
    def blank_to_nil(hash)
      hash.inject({}){|h,(k,v)|
        h.merge(
          k => case v
          when Hash  : blank_to_nil v
          when Array : v.map{|e| e.is_a?( Hash ) ? blank_to_nil(e) : e}
          else v == "" ? nil : v
          end
        )
      }
    end
    
    ...
    

    I've tried to keep the code as concise as possible, although readability has suffered somewhat, so here is a test case to demonstrate its functionality:

    require "test/unit"
    class BlankToNilTest < Test::Unit::TestCase
    
      def blank_to_nil(hash)
        hash.inject({}){|h,(k,v)|
          h.merge(
            k => case v
            when Hash  : blank_to_nil v
            when Array : v.map{|e| e.is_a?( Hash ) ? blank_to_nil(e) : e}
            else v == "" ? nil : v
            end
          )
        }
      end
    
      def test_should_convert_blanks_to_nil
        hash =        {:a => nil, :b => "b", :c => ""}
        assert_equal( {:a => nil, :b => "b", :c => nil}, blank_to_nil(hash) )
      end
    
      def test_should_leave_empty_hashes_intact
        hash =        {:a => nil, :b => "b", :c => {}}
        assert_equal( {:a => nil, :b => "b", :c => {}}, blank_to_nil(hash) )
      end
    
      def test_should_leave_empty_arrays_intact
        hash =        {:a => nil, :b => "b", :c => []}
        assert_equal( {:a => nil, :b => "b", :c => []}, blank_to_nil(hash) )
      end
    
      def test_should_convert_nested_hashes
        hash =        {:a => nil, :b => "b", :c => {:d => 2, :e => {:f => "",  :g => "",  :h => 5}, :i => "bar"}}
        assert_equal( {:a => nil, :b => "b", :c => {:d => 2, :e => {:f => nil, :g => nil, :h => 5}, :i => "bar"}}, blank_to_nil(hash) )
      end
    
      def test_should_convert_nested_hashes_in_arrays
        hash =        {:book_attributes => [{:name => "b", :isbn => "" },{:name => "c", :isbn => "" }], :shelf_id => 2}
        assert_equal( {:book_attributes => [{:name => "b", :isbn => nil},{:name => "c", :isbn => nil}], :shelf_id => 2}, blank_to_nil(hash))
      end
    
      def test_should_leave_arrays_not_containing_hashes_intact
        hash =        {:as => ["", nil, "foobar"]}
        assert_equal( {:as => ["", nil, "foobar"]}, blank_to_nil(hash))
      end
    
      def test_should_work_with_mad_combination_of_arrays_and_hashes
        hash =        {:as => ["", nil, "foobar", {:b => "b", :c => "",  :d => nil, :e => [1,2,3,{:a => "" }]}]}
        assert_equal( {:as => ["", nil, "foobar", {:b => "b", :c => nil, :d => nil, :e => [1,2,3,{:a => nil}]}]}, blank_to_nil(hash))
      end
    
    end
    

    This can then be used in a controller like so:

    ...
    @book.update_attributes(clean_params[:book])
    ...
    
    0 讨论(0)
提交回复
热议问题