Skip to content

Instantly share code, notes, and snippets.

@joakimk
Created August 29, 2012 17:12
Show Gist options
  • Save joakimk/3515735 to your computer and use it in GitHub Desktop.
Save joakimk/3515735 to your computer and use it in GitHub Desktop.
A simple form object built on top of virtus.
class Filter
include FormObject
# Proc because Date.yesterday changes every day :)
attribute :from, Date, default: Proc.new { Date.yesterday }
attribute :to, Date, default: Proc.new { 1.month.from_now - 1.day }
end
# in controller
@filter = Filter.new(params[:filter])
@orders = Orders.between(@filter.from, @filter.to)
# in view
@filter.from # always a date, either a user entered date or the default date
# Ensures values are either the type you expect, a default value or nil.
#
# Virtus is built to handle data from a database where it's either well formed or nil. We need
# to tweak it's return values a little bit for it to handle form data. See https://github.com/solnic/virtus/issues/99.
module FormObject
include Virtus
module ClassMethods
def attribute(name, type, opts = {})
super(name, type, opts)
define_method(name) do
data = super()
if data.is_a?(type)
data
elsif opts[:default]
opts[:default].call
else
nil
end
end
end
end
def self.included(descendant)
super
descendant.extend FormObject::ClassMethods
end
end
require 'spec_helper'
require 'form_object'
class Filter
include FormObject
attribute :from, Date, default: Proc.new { Date.yesterday }
attribute :number, Integer
end
describe FormObject do
it "can handle data from a form" do
filter = Filter.new(from: "2012-01-15")
filter.from.should be_kind_of(Date)
filter.from.should == Date.parse("2012-01-15")
end
it "defaults" do
filter = Filter.new
filter.from.should == Date.yesterday
end
it "defaults when it can't parse a value" do
filter = Filter.new(from: "2012-01-55")
filter.from.should == Date.yesterday
end
it "returns nil when it can't parse the value and there is no default" do
filter = Filter.new(number: "2012-01-55")
filter.number.should be_nil
end
it "returns nil when there is no default" do
filter = Filter.new
filter.number.should be_nil
end
end
@joevandyk
Copy link

This fails if the type is an Array of something, like attribute :addresses, Array[Address]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment