diff --git a/README.md b/README.md
index a965af0..3b91f27 100644
--- a/README.md
+++ b/README.md
@@ -13,6 +13,8 @@ attributes are stripped of whitespace, but `:only` and `:except`
options can be used to limit which attributes are stripped. Both options accept
a single attribute (`only: :field`) or arrays of attributes (`except: [:field1, :field2, :field3]`).
+It's also possible to skip stripping the attributes altogether per model using the `:if` and `:unless` options.
+
---
**How You Can Help**
@@ -67,6 +69,32 @@ class ConservativePokerPlayer < ActiveRecord::Base
end
```
+### Using `if`
+
+```ruby
+# Only records with odd ids will be stripped
+class OddPokerPlayer < ActiveRecord::Base
+ strip_attributes if: :strip_me?
+
+ def strip_me?
+ id.odd?
+ end
+end
+```
+
+### Using `unless`
+
+```ruby
+# strip_attributes will be applied randomly
+class RandomPokerPlayer < ActiveRecord::Base
+ strip_attributes unless: :strip_me?
+
+ def strip_me?
+ [true, false].sample
+ end
+end
+```
+
### Using `allow_empty`
```ruby
diff --git a/lib/strip_attributes.rb b/lib/strip_attributes.rb
index 86e10c9..de36b66 100644
--- a/lib/strip_attributes.rb
+++ b/lib/strip_attributes.rb
@@ -2,24 +2,24 @@
module ActiveModel::Validations::HelperMethods
# Strips whitespace from model fields and converts blank values to nil.
- def strip_attributes(options = nil)
+ def strip_attributes(options = {})
StripAttributes.validate_options(options)
- before_validation do |record|
+ before_validation(options.slice(:if, :unless)) do |record|
StripAttributes.strip(record, options)
end
end
# DEPRECATED: Please use strip_attributes (non-bang method)
# instead.
- def strip_attributes!(options = nil)
+ def strip_attributes!(options = {})
warn "[DEPRECATION] `strip_attributes!` is deprecated. Please use `strip_attributes` (non-bang method) instead."
strip_attributes(options)
end
end
module StripAttributes
- VALID_OPTIONS = [:only, :except, :allow_empty, :collapse_spaces, :replace_newlines, :regex]
+ VALID_OPTIONS = [:only, :except, :allow_empty, :collapse_spaces, :replace_newlines, :regex, :if, :unless]
# Unicode invisible and whitespace characters. The POSIX character class
# [:space:] corresponds to the Unicode class Z ("separator"). We also
@@ -37,7 +37,7 @@ module StripAttributes
MULTIBYTE_BLANK = /[[:blank:]#{MULTIBYTE_WHITE}]/
MULTIBYTE_SUPPORTED = "\u0020" == " "
- def self.strip(record_or_string, options = nil)
+ def self.strip(record_or_string, options = {})
if record_or_string.respond_to?(:attributes)
strip_record(record_or_string, options)
else
@@ -45,7 +45,7 @@ def self.strip(record_or_string, options = nil)
end
end
- def self.strip_record(record, options = nil)
+ def self.strip_record(record, options = {})
attributes = narrow(record.attributes, options)
attributes.each do |attr, value|
@@ -57,13 +57,11 @@ def self.strip_record(record, options = nil)
record
end
- def self.strip_string(value, options = nil)
- if options
- allow_empty = options[:allow_empty]
- collapse_spaces = options[:collapse_spaces]
- replace_newlines = options[:replace_newlines]
- regex = options[:regex]
- end
+ def self.strip_string(value, options = {})
+ allow_empty = options[:allow_empty]
+ collapse_spaces = options[:collapse_spaces]
+ replace_newlines = options[:replace_newlines]
+ regex = options[:regex]
if value.respond_to?(:strip)
value = (value.blank? && !allow_empty) ? nil : value.strip
@@ -97,10 +95,10 @@ def self.strip_string(value, options = nil)
# Necessary because Rails has removed the narrowing of attributes using :only
# and :except on Base#attributes
def self.narrow(attributes, options = {})
- if except = options && options[:except]
+ if except = options[:except]
except = Array(except).collect { |attribute| attribute.to_s }
attributes.except(*except)
- elsif only = options && options[:only]
+ elsif only = options[:only]
only = Array(only).collect { |attribute| attribute.to_s }
attributes.slice(*only)
else
@@ -109,7 +107,7 @@ def self.narrow(attributes, options = {})
end
def self.validate_options(options)
- if keys = options && options.keys
+ if keys = options.keys
unless (keys - VALID_OPTIONS).empty?
raise ArgumentError, "Options does not specify #{VALID_OPTIONS} (#{options.keys.inspect})"
end
diff --git a/test/strip_attributes_test.rb b/test/strip_attributes_test.rb
index 6fdb8bc..4811e2a 100644
--- a/test/strip_attributes_test.rb
+++ b/test/strip_attributes_test.rb
@@ -9,6 +9,8 @@ def self.included(base)
base.attribute :bang
base.attribute :foz
base.attribute :fiz
+ base.attribute :strip_me
+ base.attribute :skip_me
end
end
@@ -72,6 +74,29 @@ class StripRegexMockRecord < Tableless
strip_attributes regex: /[\^\%&\*]/
end
+class IfSymMockRecord < Tableless
+ include MockAttributes
+ strip_attributes if: :strip_me?
+
+ def strip_me?
+ strip_me
+ end
+end
+
+class UnlessSymMockRecord < Tableless
+ include MockAttributes
+ strip_attributes unless: :skip_me?
+
+ def skip_me?
+ skip_me
+ end
+end
+
+class IfProcMockRecord < Tableless
+ include MockAttributes
+ strip_attributes if: Proc.new { |record| record.strip_me }
+end
+
class StripAttributesTest < Minitest::Test
def setup
@init_params = {
@@ -242,6 +267,78 @@ def test_should_strip_unicode
assert_equal "foo", record.foo
end
+ def test_should_strip_all_fields_if_true
+ record = IfSymMockRecord.new(@init_params.merge(strip_me: true))
+ record.valid?
+ assert_equal "foo", record.foo
+ assert_equal "bar", record.bar
+ assert_equal "biz", record.biz
+ assert_equal "foz foz", record.foz
+ assert_equal "fiz \n fiz", record.fiz
+ assert_nil record.baz
+ assert_nil record.bang
+ end
+
+ def test_should_strip_no_fields_if_false
+ record = IfSymMockRecord.new(@init_params.merge(strip_me: false))
+ record.valid?
+ assert_equal "\tfoo", record.foo
+ assert_equal "bar \t ", record.bar
+ assert_equal "\tbiz ", record.biz
+ assert_equal " foz foz", record.foz
+ assert_equal "fiz \n fiz", record.fiz
+ assert_equal "", record.baz
+ assert_equal " ", record.bang
+ end
+
+ def test_should_strip_all_fields_unless_false
+ record = UnlessSymMockRecord.new(@init_params.merge(skip_me: false))
+ record.valid?
+ assert_equal "foo", record.foo
+ assert_equal "bar", record.bar
+ assert_equal "biz", record.biz
+ assert_equal "foz foz", record.foz
+ assert_equal "fiz \n fiz", record.fiz
+ assert_nil record.baz
+ assert_nil record.bang
+ end
+
+ def test_should_strip_no_fields_unless_true
+ record = UnlessSymMockRecord.new(@init_params.merge(skip_me: true))
+ record.valid?
+ assert_equal "\tfoo", record.foo
+ assert_equal "bar \t ", record.bar
+ assert_equal "\tbiz ", record.biz
+ assert_equal " foz foz", record.foz
+ assert_equal "fiz \n fiz", record.fiz
+ assert_equal "", record.baz
+ assert_equal " ", record.bang
+ end
+
+ def test_should_strip_all_fields_if_true_proc
+ record = IfProcMockRecord.new(@init_params.merge(strip_me: true))
+ record.valid?
+ assert_equal "foo", record.foo
+ assert_equal "bar", record.bar
+ assert_equal "biz", record.biz
+ assert_equal "foz foz", record.foz
+ assert_equal "fiz \n fiz", record.fiz
+ assert_nil record.baz
+ assert_nil record.bang
+ end
+
+ def test_should_strip_no_fields_if_false_proc
+ record = IfProcMockRecord.new(@init_params.merge(strip_me: false))
+ record.valid?
+ assert_equal "\tfoo", record.foo
+ assert_equal "bar \t ", record.bar
+ assert_equal "\tbiz ", record.biz
+ assert_equal " foz foz", record.foz
+ assert_equal "fiz \n fiz", record.fiz
+ assert_equal "", record.baz
+ assert_equal " ", record.bang
+ end
+
class ClassMethodsTest < Minitest::Test
def test_should_strip_whitespace
assert_nil StripAttributes.strip("")