InFormat
Easily add custom getter and setter filters for attributes on ActiveRecord objects. These can be useful if you wish to scrub data before it hits your datastore and/or provide uniformity when reading.
Requirements
For Ruby 1.9.0 and greater. Tested with Rails 3.1+ using ActiveRecord. It should work with any ORM that provides a hash syntax for accessing attributes in Models (please let me know if you have success/failures with other ORMs).
Installation
Add the requirement to your Gemfile
gem "in_format"
That's it if using ActiveRecord. If using a different ORM you will need to extend InFormat
on the models, add an initializer or shoehorn it in some other way.
Usage
Invoke in_format
, phone_format
or ssn_format
in your Model for attributes you wish to process.
in_format
The in_format
method is the most general and accepts a getter and/or a setter.
Under the hood these create setters/getters and process the value through the supplied Proc/lambda and set/read the value using the hash syntax (self[:attribute_name]
).
There is an use_accessor
option which will override getter/setter methods matching the attribute. This can be useful if you want to combine in_format
with attr_accessor
or gems like attr_encrypted (just be sure that the overridden methods exist before using in_format
).
You can access the original getter by passing true
to the new one (assuming you supplied a getter).
class MyModel < ActiveRecord::Base
in_format :name, setter: lambda {|v| v.upcase }, getter: lambda {|v| "Mrs. #{v}"}
attr_accessor :some_attribute
in_format :some_attribute, use_accessor: true, setter: -> v { "#{v}s"}, getter: -> v { "3 {v}"}
end
m = MyModel.new(name: "shirley") m.name(true) #=> "SHIRLEY" m.name #=> "Mrs. SHIRLEY" m.some_attribute = "beer" m.some_attribute(true) #=> "beers" m.some_attribute #=> "3 beers"
This example is contrived and a little dangerous, MyModel.new(name: nil) #=> splode!
, but you can do a lot with getters/setters.
phone_format
phone_format
uses in_format
with some pre-defined getters and setters.
class MyModel < ActiveRecord::Base
phone_format :phone
phone_format :phone_without_getter, getter: false
end
m = MyModel.new(phone: "(213) 222-2222", phone_without_getter: "(213) 222-2222") m.name(true) #=> "2132222222" m.name #=> "222-222-2222" m.phone_without_getter #=> "2132222222"
You can supply your own getter or setter like in_format
if the defaults don't match your needs or you can pass a getter or setter with false
to exclude it.
ssn_format
ssn_format
works much like phone_format
, also accepts custom getters/setters.
class MyModel < ActiveRecord::Base
ssn_format :ssn
end
or with attr_encrypted
class MyModel < ActiveRecord::Base
attr_encrypted :ssn # defined before call to ssn_format
ssn_format :ssn, use_accessor: true
end
m = MyModel.new(ssn: "123 45 6789") m.name(true) #=> "123456789" m.name #=> "123-45-6789"
Reccomendations
If you have getters/setters you would like to re-use across many attributes or classes I would stick em all in a (well-tested) module and keep an eye out for edge cases. You can also use in_format
as the base for your own custom methods like phone_format
, etc.
module MyFormatters
CAPS = -> v { |v| v ? v.to_s.capitalize : "Generic Dog Name" }
NO_CATS = lambda do |v|
if v =~ /cat/
v.gsub("cat", "")
else
v
end
end
end
class MyModel < ActiveRecord::Base
in_format :dog_name, setter: MyFormatters::NO_CATS, getter: MyFormatters::CAPS
end
Upcoming
Currently this is written specifically for ActiveRecord but I hope to make it compatible with more ORMs. In the meantime you can use the alias option and it should work with any ruby class.
License
- Freely distributable and licensed under the MIT license.
- Copyright (c) 2012 Cyrus Farajpour (smoils@gmail.com)