让空白PARAMS []无(Make blank params[] nil)

2019-06-26 19:33发布

当用户提交一个表单,并留有一定领域的空白,他们得到保存在数据库中的空白。 我想通过PARAMS迭代[:用户]集合(例如),如果字段为空白,更新属性之前将其设置为零。 我无法弄清楚如何做到这一点,虽然我知道迭代的唯一方法创建新的对象:

coll = params[:user].each do |c|
    if c == ""
       c = nil
    end
end

谢谢。

Answer 1:

考虑你正在使用的过滤器在控制器中保存的影响或更新时模型的行为在这里做什么。 我认为一个更清洁的方法将是一个before_save回调模型或观察员。 这样,你得到相同的行为无论在哪里变化经由控制器,控制台甚至运行批处理过程时,无论其起源。

例:

class Customer < ActiveRecord::Base
  NULL_ATTRS = %w( middle_name )
  before_save :nil_if_blank

  protected

  def nil_if_blank
    NULL_ATTRS.each { |attr| self[attr] = nil if self[attr].blank? }
  end
end

这将产生预期的行为:

>> c = Customer.new
=> #<Customer id: nil, first_name: nil, middle_name: nil, last_name: nil>
>> c.first_name = "Matt"
=> "Matt"
>> c.middle_name = "" # blank string here
=> ""
>> c.last_name = "Haley"
=> "Haley"
>> c.save
=> true
>> c.middle_name.nil?
=> true
>>


Answer 2:

如果你只是想杀人的空白,你可以做params.delete_if {|k,v| v.blank?} params.delete_if {|k,v| v.blank?}



Answer 3:

一个良好的创业板在模型中处理此: https://github.com/rmm5t/strip_attributes

它定义了一个before_validation挂钩,修剪空格,并设置空字符串为零。



Answer 4:

before_save似乎是错误的位置给我,如果你想在保存之前使用的值是什么。 所以我推翻的制定者,而不是:

# include through module or define under active_record
def self.nil_if_blank(*args)
  args.each do |att|
    define_method att.to_s + '=' do |val|
      val = nil if val.respond_to?(:empty?) && val.empty?
      super(val)
    end
  end
end

#inside model
nil_if_blank :attr1, :attr2

只要是完整的,我把LIB / my_model_extensions.rb以下

module MyModelExtensions
  def self.included(base)
    base.class_eval do
      def self.nil_if_blank(*args)
        args.each do |att|
          define_method att.to_s + '=' do |val|
            val = nil if val.respond_to?(:empty?) && val.empty?
            super(val)
          end
        end
      end
    end
  end
end

并使用它像这样:

class MyModel
  include MyModelExtensions
  nil_if_blank :attr1, :attr2
end


Answer 5:

通常我会鼓励的功能被移动到模型中,在其他的答案说,这意味着你会得到相同的行为无论身在何处的变化从起源。

不过,我不认为在这种情况下,它是正确的。 该影响被发现纯属下降到不能够编码在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])
...


Answer 6:

您可以使用attribute_normalizer宝石和使用空白正规化,将在零值变换空字符串。



Answer 7:

你可以做到这一点使用注射,这是显而易见的,以正在发生的事情。

params = params.inject({}){|new_params, kv| 
  new_params[kv[0]] = kv[1].blank? ? nil : kv[1]
  new_params
}

还有一个黑客可以通过与自身融合,并传递一个块来处理新的价值与合并做(虽然这不是真正为它的用途,但它更简洁)

params.merge(params){|k, v| v.blank? ? nil : v}


Answer 8:

使用“到位”收集方法(也被称为地图!)

params[:user].collect! {|c| c == "" ? nil : c}


Answer 9:

克里斯,

这里是有相思值则params的递归解析。

before_filter :process_params

......



private
def process_params
....
  set_blanc_values_to_nil(params)
end

# Maybe move method to ApplicationController
# recursively sets all blanc values to nil
def set_blanc_values_to_nil!(my_hash)
    my_hash.keys.each do |key|
        val = my_hash[key]
        next if val.nil?
        my_hash[key] = nil if val.is_a?(String) && val.empty?
        set_blanc_values_to_nil!(val) if val.is_a? Hash
    end
end


Answer 10:

在ApplicationController中:

class ApplicationController < ActionController::Base

  def nilify(p)
    p.transform_values!{|v| v.present? ? v : nil }
  end

end

在你的控制器中,修改参数强滤波方法调用nilify:

class UserController < ApplicationController

  def user_params
    nilify params.require(:user).permit(:email, :name)
  end

end


Answer 11:

我广义的答案和由钩/延伸,可以用来作为一个初始值设定。 这使得它可以在多个机型上使用。 我已经添加了它作为我的一部分ActiveRecordHelpers GitHub上回购



Answer 12:

这里是我做到了。

def remove_empty_params(param, key)
  param[key] = param[key].reject { |c| c.empty? }
end

并把它与

remove_empty_params(params[:shipments], :included_clients)

没有必要让模型中的超级棘手。 而这种方式,您可以控制哪些PARAMS得到清理。

params = {
      "shipments"=>{
        "included_clients" => ["", "4"]
      }
    }

会变成

>> params["shipments"]
=> {"included_clients" => ["4"] }


Answer 13:

如果你知道你要编码空白视为尼尔斯你可以使用下面的属性二传手覆盖哪些属性:

def colour=(colour)
  super(colour.blank? ? nil : colour)
end

有点笨重,如果你有很多的属性来覆盖,虽然。



文章来源: Make blank params[] nil