Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>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.</p> <p>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).</p> <p>The code I'm using to overcome this problem is:</p> <pre><code># 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 =&gt; 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 ... </code></pre> <p>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:</p> <pre><code>require "test/unit" class BlankToNilTest &lt; Test::Unit::TestCase def blank_to_nil(hash) hash.inject({}){|h,(k,v)| h.merge( k =&gt; 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 =&gt; nil, :b =&gt; "b", :c =&gt; ""} assert_equal( {:a =&gt; nil, :b =&gt; "b", :c =&gt; nil}, blank_to_nil(hash) ) end def test_should_leave_empty_hashes_intact hash = {:a =&gt; nil, :b =&gt; "b", :c =&gt; {}} assert_equal( {:a =&gt; nil, :b =&gt; "b", :c =&gt; {}}, blank_to_nil(hash) ) end def test_should_leave_empty_arrays_intact hash = {:a =&gt; nil, :b =&gt; "b", :c =&gt; []} assert_equal( {:a =&gt; nil, :b =&gt; "b", :c =&gt; []}, blank_to_nil(hash) ) end def test_should_convert_nested_hashes hash = {:a =&gt; nil, :b =&gt; "b", :c =&gt; {:d =&gt; 2, :e =&gt; {:f =&gt; "", :g =&gt; "", :h =&gt; 5}, :i =&gt; "bar"}} assert_equal( {:a =&gt; nil, :b =&gt; "b", :c =&gt; {:d =&gt; 2, :e =&gt; {:f =&gt; nil, :g =&gt; nil, :h =&gt; 5}, :i =&gt; "bar"}}, blank_to_nil(hash) ) end def test_should_convert_nested_hashes_in_arrays hash = {:book_attributes =&gt; [{:name =&gt; "b", :isbn =&gt; "" },{:name =&gt; "c", :isbn =&gt; "" }], :shelf_id =&gt; 2} assert_equal( {:book_attributes =&gt; [{:name =&gt; "b", :isbn =&gt; nil},{:name =&gt; "c", :isbn =&gt; nil}], :shelf_id =&gt; 2}, blank_to_nil(hash)) end def test_should_leave_arrays_not_containing_hashes_intact hash = {:as =&gt; ["", nil, "foobar"]} assert_equal( {:as =&gt; ["", nil, "foobar"]}, blank_to_nil(hash)) end def test_should_work_with_mad_combination_of_arrays_and_hashes hash = {:as =&gt; ["", nil, "foobar", {:b =&gt; "b", :c =&gt; "", :d =&gt; nil, :e =&gt; [1,2,3,{:a =&gt; "" }]}]} assert_equal( {:as =&gt; ["", nil, "foobar", {:b =&gt; "b", :c =&gt; nil, :d =&gt; nil, :e =&gt; [1,2,3,{:a =&gt; nil}]}]}, blank_to_nil(hash)) end end </code></pre> <p>This can then be used in a controller like so:</p> <pre><code>... @book.update_attributes(clean_params[:book]) ... </code></pre>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload