Make blank params[] nil

前端 未结 13 600
半阙折子戏
半阙折子戏 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 18:57

    Use the "in place" collect method (also known as map!)

    params[:user].collect! {|c| c == "" ? nil : c}
    
    0 讨论(0)
  • 2020-12-13 18:59

    I generalized an answer and made a hook/extension that can be used as an initializer. This allows it to be used across multiple models. I've added it as part of my ActiveRecordHelpers repo on GitHub

    0 讨论(0)
  • 2020-12-13 19:08

    before_save seems like the wrong location to me, what if you want to use the value before saving. So I overrode the setters instead:

    # 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
    

    Just to be complete I put the following in 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
    

    and use it like this:

    class MyModel
      include MyModelExtensions
      nil_if_blank :attr1, :attr2
    end
    
    0 讨论(0)
  • 2020-12-13 19:10

    If you just want to kill the blanks, you can just do params.delete_if {|k,v| v.blank?}.

    0 讨论(0)
  • 2020-12-13 19:10

    You could do this using inject, which is obvious as to what is happening.

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

    There is also a hack you can do with merge by merging with itself, and passing a block to handle the new value (although this isn't really the intended use for it, but it is more concise)

    params.merge(params){|k, v| v.blank? ? nil : v}
    
    0 讨论(0)
  • 2020-12-13 19:12

    Consider what you're doing here by using filters in the controller to affect how a model behaves when saved or updated. I think a much cleaner method would be a before_save call back in the model or an observer. This way, you're getting the same behavior no matter where the change originates from, whether its via a controller, the console or even when running batch processes.

    Example:

    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
    

    This yields the expected behavior:

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