Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

Ticket #5694 (closed defect: fixed)

Opened 3 years ago

Last modified 2 years ago

[PATCH] Empty POST parameters result in empty string, whereas empty GET parameters result in 'nil'

Reported by: matt@drownedinsound.com Assigned to: ulysses
Priority: normal Milestone:
Component: ActionPack Version: 1.1.1
Severity: normal Keywords: action_controller query post get params empty string nil
Cc: tarmo@itech.ee

Description

The summary says it all really. I like empty form fields to result in a nil in the params hash when submitted. Currently they result in an empty string.

Regardless of whether this was a delibarate choice or not, it should at least be consistent with what happens for empty GET parameters (which current result in a nil). Otherwise controller behaviour can change in tricky and hard-to-spot ways merely as a result of changing a form's method from POST to GET.

Here is a trivial replacement for CGIMethods.get_typed_value (in cgi_ext/cgi_methods.rb) which seems to fix this for me, giving nils in both cases.

  def CGIMethods.get_typed_value(value)
    # test most frequent case first
    if value.is_a?(String)
      value.empty? ? nil : value
    elsif value.respond_to?(:content_type) && ! value.content_type.blank?
      # Uploaded file
      unless value.respond_to?(:full_original_filename)
        class << value
          alias_method :full_original_filename, :original_filename

          # Take the basename of the upload's original filename.
          # This handles the full Windows paths given by Internet Explorer   
          # (and perhaps other broken user agents) without affecting
          # those which give the lone filename.
          # The Windows regexp is adapted from Perl's File::Basename.
          def original_filename
            if md = /^(?:.*[:\\\/])?(.*)/m.match(full_original_filename)
              md.captures.first
            else
              File.basename full_original_filename
            end
          end
        end
      end

      # Return the same value after overriding original_filename.
      value

    elsif value.respond_to?(:read)
      # Value as part of a multipart request
      v = value.read
      v.empty? ? nil : v
    elsif value.class == Array
      value.collect { |v| CGIMethods.get_typed_value(v) }
    else
      # other value (neither string nor a multipart request)
      v = value.to_s
      v.empty? ? nil : v
    end
  end

Attachments

empty_parameter (142 bytes) - added by undees on 01/09/07 06:38:40.
Fixture for actionpack/test/fixtures/multipart
empty_post_parameter (0.5 kB) - added by undees on 01/09/07 06:40:44.
Patch generated from rails/actionpack/

Change History

08/03/06 14:52:49 changed by anonymous

  • component changed from ActiveRecord to ActionPack.

08/19/06 23:14:43 changed by cch1@hapgoods.com

Sounds like an excellent idea. I'm tired of putting a long list of value = nil if value = "" at the beginning of every post action in my controllers.

09/04/06 18:04:29 changed by david

  • owner changed from David to nseckar@gmail.com.

09/07/06 17:50:02 changed by ulysses

Looks reasonable. Can you provide a unit test?

09/23/06 17:46:12 changed by ulysses

  • owner changed from nseckar@gmail.com to ulysses.

11/13/06 18:57:01 changed by tarmo

  • cc set to tarmo@itech.ee.

11/13/06 19:14:42 changed by bitsweat

  • status changed from new to closed.
  • resolution set to untested.

01/09/07 06:38:40 changed by undees

  • attachment empty_parameter added.

Fixture for actionpack/test/fixtures/multipart

01/09/07 06:40:44 changed by undees

  • attachment empty_post_parameter added.

Patch generated from rails/actionpack/

01/09/07 06:43:54 changed by undees

  • status changed from closed to reopened.
  • resolution deleted.

I've added a patch to cgi_test.rb that simulates an empty form field in the accompanying fixture and compares it to nil. The test currently fails in edge Rails as of 8 Jan 2007 -- the parameter is still recorded as instead of nil.

01/28/07 16:55:14 changed by ulysses

According to DHH, the correct move it to make GET get in line with POST -- so we're going to change GET to put empty strings in params.

(follow-up: ↓ 11 ) 01/28/07 17:00:17 changed by ulysses

  • status changed from reopened to closed.
  • resolution set to fixed.

(In [6081]) Change the query parser to map empty GET params to "" rather than nil. Closes #5694.

(in reply to: ↑ 10 ) 01/28/07 19:22:33 changed by mwillson

  • status changed from closed to reopened.
  • resolution deleted.

Replying to ulysses:

(In [6081]) Change the query parser to map empty GET params to "" rather than nil. Closes #5694.

While I'm glad to see it's being made consistent, is there any particular rationale behind the decision for ""?

A lot of standard Ruby idioms are based around the use of nil with boolean operators, and I believe it would greatly behoove Rails to facilitate this, rather than require one to litter ones code excessively with boilerplate like 'unless params[:foo].blank?' :-)

Perhaps it could be made configurable?

(follow-up: ↓ 13 ) 01/28/07 22:48:24 changed by david

  • status changed from reopened to closed.
  • resolution set to fixed.

"" is what you'd expect from a text field or area that hasn't been populated. You're of course free to add a before_filter to your own application that walks through the params hash and converts "" to nil, but I don't see it as something we're going to institutionalize by making it a configuration point.

(in reply to: ↑ 12 ) 01/29/07 09:55:29 changed by mislav

Replying to david:

You're of course free to add a before_filter to your own application that walks through the params hash and converts "" to nil ...

I have a class helper added to Base:

def self.nulify_blanks_on *column
  for field in columns
    define_method("#{field}=") { |value|
      self[field] = value.blank? ? nil : value
    }
  end
end

Then, use it in models:

nulify_blanks_on :title, :body

Basically it just creates explicit setters for those fields that write nils instead of blanks.

01/29/07 12:59:10 changed by brandon

I just add the following to all my projects:

class ActiveRecord::Base
  before_validation :clear_empty_attributes
  
  protected
    def clear_empty_attributes
      @attributes.each do |key,value|
        self[key] = nil if value.blank?
      end
    end
end