CleanModel
Extensions for ActiveModel to implement multiple types of models
Installation
Add this line to your application's Gemfile:
gem 'clean_model'
And then execute:
$ bundle
Or install it yourself as:
$ gem install clean_model
Basic models
Class definitions
class Person
include CleanModel::Base
attribute :first_name
attribute :last_name
end
Usage
person = Person.new first_name: 'John', last_name: 'Doe'
person.first_name -> 'John'
person.last_name -> 'Doe'
person.attributes -> {first_name: 'John', last_name: 'Doe'}
person.assign_attributes first_name: 'Jorge'
person.attributes -> {first_name: 'Jorge', last_name: 'Doe'}
Defaults
class Person
include CleanModel::Base
attribute :first_name, default: 'John'
attribute :last_name
end
person = Person.new
person.first_name -> 'John'
person.last_name -> nil
Active Model validations
class Person
include CleanModel::Base
attribute :first_name
attribute :last_name
validates_presence_of :first_name, :last_name
end
person = Person.new
person.valid? -> false
Strong typing
class Engine
include CleanModel::Base
attribute :power, class_name: :numeric
attribute :cylinders, class_name: :integer
attribute :valves, class_name: 'Integer'
end
engine = Engine.new
engine.power = 130
engine.cylinders = 6.1 -> Raise error CleanModel::InvalidTypeAssignment
Transformations
class Car
include CleanModel::Base
attribute :brand
attribute :model
attribute :engine, class_name: 'Engine'
attribute :comfort, transformation: lambda { |v| v.is_a?(String) ? v.split(',').map(&:strip) : v }
end
car = Car.new do |c|
c.engine = {power: 110, cylinders: 16, valves: 6}
end
car.engine -> <Engine @power=110, @cylinders=16, @valves=6>
car = Car.new do |c|
c.comfort = 'bluetooth, gps, electric pack'
end
car.comfort -> ['bluetooth', 'gps', 'electric pack']
Collections
class Factory
include CleanModel::Base
attribute :cars, collection: 'Car'
end
factory = Factory.new do |f|
f.cars = [
{brand: 'Honda', model: 'Civic'},
{brand: 'Toyota', model: 'Corolla'},
]
end
factory.cars -> [<Car @brand=Honda, @model=Civic>, <Car @brand=Toyota, @model=Corolla>]
Models with custom persistence
Definition
class Post
include CleanModel::Persistent
attribute :subject
attribute :content
private
def create
...
end
def update
...
end
def delete
...
end
end
Usage
Post.create(subject: 'Title', content: 'Some text')
or
post = Post.new subject: 'Title', content: 'Some text'
post.save
post.content = 'Another text'
post.save
post.update_attributes(title: 'Another title')
post.destroy
Remote models (for REST APIs)
Definition
class User
include CleanModel::Remote
connection host: 'localhost', port: 9999
attribute :first_name
attribute :last_name
attribute :email
def self.find(id)
connection.get "/users/#{id}.json" do |response|
new JSON.parse(response.body)
end
end
private
def create
connection.post! '/users/create.json', wrapped_attributes
end
def update
connection.put! "/users/#{id}.json", wrapped_attributes(except: :id)
end
def delete
connection.delete!("/users/#{id}.json")
end
end
Usage
User.create first_name: 'John', last_name: 'Doe'
user = User.find(1)
user.update_attributes(first_name: 'Jorge')
user.destroy
Contributing
- Fork it
- Create your feature branch (
git checkout -b my-new-feature
) - Commit your changes (
git commit -am 'Added some feature'
) - Push to the branch (
git push origin my-new-feature
) - Create new Pull Request