Skip to content

SnappFr/rails-value-object

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

6 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ValueObject

Value object management for Rails Active Records.

Override getters and setters using custom value object to dry active records from flooding logic.

Tested with Rails 5.

Installation

Add this line to your application's Gemfile :

gem 'value_object', git: '[email protected]:Snapp-FidMe/rails-value-object.git'

And then execute :

$ bundle

Monkey patch

Uniqueness validator will blow cast type error. Add this in initializer :

ActiveRecord::Base.connection.class.send(:define_method, :type_cast) do |value, column = nil|
  if value.is_a?(ValueObject::Base)
    super(value.value, column)
  else
    super(value, column)
  end
end
ActiveRecord::Base.connection.class.send(:define_method, :quote) do |value|
  if value.is_a?(ValueObject::Base)
    super(value.value)
  else
    super(value)
  end
end

Usage

Considering model User migrated with :

class CreateUsers < ActiveRecord::Migration[5.1]
  def change
    create_table :users do |t|
      t.datetime :birthdate
      t.string :paypal_id
      t.string :email
    end
  end
end

Basic usage

We can create an email value object :

class Email < ValueObject::Base

end

And use it in our model :

class User < ApplicationRecord
  extend ValueObject::Accessor

  value_object_accessor :email
end

user = User.new(email: '[email protected]')
user.email #=> value object

We can give directly a value object as attribute :

user = User.new(email: Email.new('[email protected]'))
user.email #=> value object

Accessor use a value object name equal to targeted attribute. We can user another value object type :

class User < ApplicationRecord
  extend ValueObject::Accessor

  value_object_accessor :email
  value_object_accessor :paypal_id, Email
end

user = User.new(paypal_id: '[email protected]')
user.paypal_id #=> Email value object

Methods

Email.new(nil).nil? #=> true
Email.new(nil).present? #=> false

Email.new('').blank? #=> true
Email.new('').present? #=> false

Email.new('[email protected]').present? #=> true

Email.new('[email protected]') == Email.new('[email protected]') #=> true

Email.new('[email protected]') <=> Email.new('[email protected]') #=> 0

Email.new('[email protected]').value #=> '[email protected]'

Email.new('[email protected]').to_s #=> '[email protected]'

Email.new('[email protected]').to_json #=> "\"[email protected]\""

Email.new('[email protected]').as_json #=> '[email protected]'

Basic validation

Use custom rails validation when needed.

class Email < ValueObject::Base
  FORMAT = /\A([\w+\-].?)+@[a-z\d\-]+(\.[a-z]+)*\.[a-z]+\z/i

  validator

  def valid?
    value.present? && value.match(FORMAT).present?
  end
end

class User < ApplicationRecord
  extend ValueObject::Accessor

  value_object_accessor :email

  validates :email, presence: true, email: { allow_nil: true }
end

user = User.new(email: '[email protected]')
user.valid? #=> true

user = User.new(email: 'wrong')
user.valid? #=> false, error message at email: :invalid

Custom Validation

Can user validator DSL to give specific validation :

class Birthdate < ValueObject::Base

  validator name: 'MajorityValidator', with: ->(record, attribute, value) do
    record.errors.add(:birthdate, :too_young) if value.present? && value.younger_than(18)?
  end

  def younger_than(age)?
    value > Time.zone.now - age.years
  end
end

class User < ApplicationRecord
  extend ValueObject::Accessor

  value_object_accessor :birthdate

  validates :birthdate, majority: true
end

user = User.new(birthdate: Time.zone.now - 19.years)
user.valid? #=> true

user = User.new(birthdate: Time.zone.now - 17.years)
user.valid? #=> false, error message at birthdate: :too_young

TODO

  • method_missing redirect method to inner value
  • custom validator options to make simpler
  • explicit exception when validator override already existing validator

License

The gem is available as open source under the terms of the MIT License.

About

Value object management for rails active records

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published