Skip to content

Instantly share code, notes, and snippets.

@stefanoverna
Last active August 29, 2015 14:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save stefanoverna/4345186ee51019b147a3 to your computer and use it in GitHub Desktop.
Save stefanoverna/4345186ee51019b147a3 to your computer and use it in GitHub Desktop.
require "virtus"
module Commands
module Base
def self.included(base)
base.extend ClassMethods
base.include Virtus.model
base.include ActiveModel::Validations
base.prepend InstanceMethods
end
module ClassMethods
def call(*args)
new(*args).call
end
end
module InstanceMethods
def call
valid? || raise_with_errors(errors)
super
end
protected
def raise_with_errors(errors)
raise InvalidDataError.new(errors)
end
end
end
end
module Commands
class CommitUser
include Base
attribute :hour, Integer
attribute :date, Date
attribute :user
attribute :project
validate :check_hour_is_in_working_hours
validate :check_date_is_in_the_future
def call
if commitment
commitment.update_attributes(project: project)
commitment
else
Models::Commitment.create!(attributes)
end
rescue ActiveRecord::RecordInvalid => invalid
raise_with_errors invalid.record.errors
end
protected
def check_hour_is_in_working_hours
unless Services::WorkingHours.working_hour?(hour)
errors.add(:hour, :working_hours)
end
end
def check_date_is_in_the_future
if date && date < Date.today
errors.add(:date, :in_future)
end
end
def commitment
@commitment ||= Models::Commitment.
where(attributes.slice(:user, :date, :hour)).first
end
end
end
module Commands
class InvalidDataError < RuntimeError
attr_reader :details
def initialize(errors = {})
@details = errors
end
def to_s
super + "\n" + errors_to_s
end
def as_json(*args)
details.map do |attribute, error|
{
attribute: attribute,
reason: error
}
end.as_json(*args)
end
protected
def errors_to_s
buf = ["Errors:"]
details.each do |attribute, error|
buf << "* #{attribute}: #{error}"
end
buf.join("\n")
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment