Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ActiveRecord: make all text fields have strip called on them before saving, unless specified otherwise

I've ran into various problems with various sites over the years with users putting spaces at the start/end of string and text fields. Sometimes these cause formatting/layout problems, sometimes they cause searching problems (ie search order looking wrong even though it isn't really), sometimes they actually crash the app.

I thought it would be useful, rather than putting in a bunch of before_save callbacks as i have done in the past, to add some functionality to ActiveRecord to automatically call .strip on any string/text fields before saving, unless i tell it not to, eg with do_not_strip :field_x, :field_y or something similar at the top of the class definition.

Before i go and figure out how to do this, has anyone seen a nicer solution? Just to be clear, i already know that i can do this:

before_save :strip_text_fields

def strip_text_fields
  self.field_x.strip!
  self.field_y.strip!
end

but i'm looking for a nicer way.

cheers, max

like image 291
Max Williams Avatar asked Jun 27 '11 11:06

Max Williams


3 Answers

Here's a handy module that you could drop into lib and include in your models. It doesn't have the exceptions that you mentioned, but it looks for a strip! method which might be good enough. You could add the exceptions feature fairly easily, if needed.

# lib/attribute_stripping.rb
module AttributeStripping

  def self.included(context)
    context.send :before_validation, :strip_whitespace_from_attributes
  end

  def strip_whitespace_from_attributes
    attributes.each_value { |v| v.strip! if v.respond_to? :strip! }
  end

end

Use like this:

class MyModel < ActiveRecord::Base
    include AttributeStripping

    # ...
end

UPDATE (9/10/2013):

Revisiting this answer a couple of years later, I see how the winds have changed. There's a cleaner way to do it now. Create a module like this:

module AttributeStripper

  def self.before_validation(model)
    model.attributes.each_value { |v| v.strip! if v.respond_to? :strip! }
    true
  end

end

and set its method to be invoked at the right time in your model:

class MyModel < ActiveRecord::Base
  before_validation AttributeStripper

  # ...
end

This module is easier to test since it's not a mixin.

like image 135
Rob Davis Avatar answered Oct 22 '22 17:10

Rob Davis


I have dealt with these sort of data integrity issues in various applications.

I used to manipulate the input like that.

But now, the best advice I have actually seen and followed is to store whatever the user types. Then do post-processing on the backend to do the strip. Create additional database fields (destripped) if you really want it in the database model table.

The main reason for this is one (primary) thing - when users want to revisit their data, i.e. edit, they're usually gonna expect to see what they typed in. A secondary reason is that you will avoid the possibility that your strip doesn't work right and either mangles the data or actually throw an error.

like image 40
Michael Durrant Avatar answered Oct 22 '22 18:10

Michael Durrant


I've written a plugin for this purpose some time ago. I haven't tried it in a while and it doesn't have tests - so no guaranties that it still works. The upside would be a clean model:

class Story < ActiveRecord::Base
  strip_strings :title, :abstract, :text
end
like image 33
Wukerplank Avatar answered Oct 22 '22 18:10

Wukerplank