Обычно я стимулировала бы функциональность перенести в модель, как указано в других ответах это означает, что вы получите такое же поведение независимо от того, откуда происходит изменение.
Однако, я не думаю, что в этом случае это правильно. Аффект, замеченный, сводится к тому, что он не может кодировать разницу между пустой строкой и значением nil в HTTP-запросе. По этой причине он должен быть исправлен на уровне контроллера. Это также означает, что в других местах по-прежнему можно сохранить пустую строку в модели (что может быть по какой-то законной причине, а если нет, то просто ее можно покрыть стандартными проверками).
код, я использую, чтобы преодолеть эту проблему:
# 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
...
Я пытался сохранить код как можно более кратким, хотя читаемость страдал несколько, так вот тест, чтобы продемонстрировать его функциональность:
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
Это может быть затем использован в контроллере так:
...
@book.update_attributes(clean_params[:book])
...
Вместо того, чтобы ждать позже, почему бы не построить это в логике формы? По мере того, как значения собираются, поставьте чек, который переключает 'nil' для любой записи, содержащей только пробельные символы или вообще ничего. Таким образом, пробелы никогда не попадают в сохраненные значения. – Telemachus
Я думаю, проблема в том, что значения nil не будут перезаписывать значение db. – chrishomer
Поскольку это теперь находится на первой странице Google для соответствующего поиска, обратите внимание на других поисковиков: теперь есть драгоценный камень, который сделает это автоматически для вас - https://github.com/grosser/clear_empty_attributes –