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
Use the "in place" collect method (also known as map!)
params[:user].collect! {|c| c == "" ? nil : c}
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
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
If you just want to kill the blanks, you can just do params.delete_if {|k,v| v.blank?}
.
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}
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
>>