https://github.com/anthonator/soulless
Rails models without the database (and Rails)
https://github.com/anthonator/soulless
Last synced: 9 months ago
JSON representation
Rails models without the database (and Rails)
- Host: GitHub
- URL: https://github.com/anthonator/soulless
- Owner: anthonator
- License: mit
- Created: 2013-10-30T16:57:44.000Z (over 12 years ago)
- Default Branch: master
- Last Pushed: 2018-04-26T14:16:13.000Z (about 8 years ago)
- Last Synced: 2025-03-18T17:24:33.372Z (over 1 year ago)
- Language: Ruby
- Homepage:
- Size: 105 KB
- Stars: 5
- Watchers: 2
- Forks: 2
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE.txt
- Code of conduct: CODE_OF_CONDUCT.md
Awesome Lists containing this project
README
# Soulless
Rails models without the database (and Rails). Great for implementing the form object pattern.
[](https://travis-ci.org/anthonator/soulless) [](https://gemnasium.com/anthonator/soulless)
[](https://coveralls.io/r/anthonator/soulless?branch=master) [](https://codeclimate.com/github/anthonator/soulless)
## Installation
Add this line to your application's Gemfile:
gem 'soulless'
And then execute:
$ bundle
Or install it yourself as:
$ gem install soulless
## Usage
Just define a plain-old-ruby-object, inherit from `Soulless::Model` and get crackin'!
```ruby
class UserSignupForm < Soulless::Model
attribute :name, String
attribute :email, String
attribute :password, String
validates :name, presence: true
validates :email, presence: true,
uniqueness: { model: User }
validates :password, presence: true,
lenght: { is_at_least: 8 }
end
```
### Validations and Errors
Soulless lets you define your validations and manage your errors just like you did in Rails.
```ruby
class UserSignupForm < Soulless::Model
...
validates :name, presence: true
validates :email, presence: true,
uniqueness: { model: User }
validates :password, presence: true,
lenght: { minimum: 8 }
...
end
```
Check to see if your object is valid by calling `valid?`.
```ruby
form = UserSignupForm.new(name: name, email: email)
form.valid? # => false
```
See what errors are popping up using the `errors` attribute.
```ruby
form = UserSignupForm.new(name: name, email: email)
form.valid?
form.errors[:password] # => ["is too short (minimum is 8 characters)"]
```
#### Uniqueness Validations
If you're using Soulless in Rails it's even possible to validate uniqueness.
```ruby
class UserSignupForm < Soulless::Model
...
validates :primary_email, presence: true,
uniqueness: { model: User, attribute: :email }
...
end
```
Just let the validator know what ActiveRecord model to use when performing the validation using the `model` option.
If your Soulless object attribute doesn't match up to the ActiveRecord model attribute just map it using the `attribute` option.
### Callbacks
Soulless supports the validation callback. You can use this callback as you
would on a Rails model.
```ruby
class Person < Soulless::Model
attribute :name, String
validates :name, presence: true
before_validation :change_name_to_bart_simpson
private
def change_name_to_bart_simpson
self.name = 'Bart Simpson'
end
end
person = Person.new(name: 'Anthony')
person.valid?
person.name # => "Bart Simpson"
```
### Dirty Attributes
Dirty attribute allow you to track changes to a Soulless object before it's saved.
```ruby
person = Person.name(name: "Anthony", spouse: { name: "Mary Jane Watson" })
person.name = 'Peter Parker'
person.changed? # => true
person.changed # => ["name"]
person.changes # => { name: ["Anthony", "Peter Parker"] }
person.name_changed? # => true
person.name_was # => "Anthony"
person.name_change # => ["Anthony", "Peter Parker"]
```
### Inheritance
One of the biggest pitfalls of the form object pattern is duplication of code. It's not uncommon for a form object to define attributes and validations that are identical to the model it represets.
To get rid of this annoying issue Soulless implements the `#inherit_from(klass, options = {})` method. This method will allow a Soulless model to inherit attributes and validations from any Rails model, Soulless model or Virtus object.
```ruby
class User < ActiveRecord::Base
validates :name, presence: true
validates :email, presence: true,
uniqueness: { case_insensitive: true }
end
```
```ruby
class UserSignupForm < Soulless::Model
inherit_from(User)
end
```
The `UserSignupForm` has automatically been defined with the `name` and `email` attributes and validations.
```ruby
UserSignupForm.attributes # => name and email attributes
form = UserSignupForm.new
form.valid? # => false
form.errors.messages # => { name: ["can't be blank"], email: ["can't be blank"] }
```
If your model is using the uniqueness validator it will automatically convert it to the [uniqueness validator provided by Soulless](https://github.com/anthonator/soulless#uniqueness-validations).
The `#inherit_from(klass, options = {})` method also allows you to provide options for managing inherited attributes.
If you don't want to inherit the `email` attribute define it using the `exclude` option.
```ruby
class UserSignupForm < Soulless::Model
inherit_from(User, exclude: :email)
end
UserSignupForm.attributes # => email will not be inherited
form = UserSignupForm.new
form.valid? # => false
form.errors.messages # => { name: ["can't be blank"] }
```
You can also flip it around if you only want the `name` attribute by using the `only` option.
```ruby
class UserSignupForm < Soulless::Model
inherit_from(User, only: :name)
end
UserSignupForm.attributes # => email will not be inherited
form = UserSignupForm.new
form.valid? # => false
form.errors.messages # => { name: ["can't be blank"] }
```
#### Available Options
`only` - Only inherit the attributes and validations for the provided attributes. Any attributes not specified will be ignored. Accepts strings, symbols and an array of strings or symbols.
`exclude` - Don't inherit the attributes and validations for the provided attributes. Accepts strings, symbols and an array of strings or symbols.
`skip_validators` - Only inherit attributes. Don't inherit any validators. Accepts a boolean.
`use_database_default` - Use the value of the `default` migration option as the default value for an attribute. Accepts either a boolean (for all attributes), a string or symbol for a single attribute or an array of strings and symbols for multiple attributes.
`additional_attributes` - Used to specify attributes that cannot automatically be added to the form model. These are generally attributes that have been specified using `attr_accessor`. Accepts a string, symbol or an array of strings and symbols for multiple attributes.
`validate_attribute_on` - By default any validation that specifies an `:on` option will not be inherited. This option will allow you to inherit a validator that uses the `:on` with a specific value. Example usage: `validate_password_on: :create`. Accepts a string or symbol. This option will accept any value that the Rails `:on` validator option can accept.
### Serialization
Soulless automatically handles serializing and deserializing Soulless models
using the standard ActiveRecord serialization methods. Serialization currently
only handles JSON and array data types.
```ruby
class Profile < Soulless::Model
attribute :first_name, String
attribute :last_name, String
...
end
class User < ActiveRecord::Base
serialize :profile, Profile
...
end
user = User.new
user.profile = { first_name: 'Anthony', last_name: 'Smith' }
user.profile # => Profile(first_name: 'Anthony', last_name: 'Smith')
```
If you want to implement your own serialization/deserialization process just
implement your own `self.load(value)` and `self.dump(value)` methods on your
model.
### I18n
Define locales similar to how you would define them in Rails.
```yaml
en:
soulless:
errors:
models:
person:
attributes:
name:
blank: "there's nothing here"
```
## Contributing
1. Fork it
2. Create your feature branch (`git checkout -b my-new-feature`)
3. Commit your changes (`git commit -am 'Add some feature'`)
4. Push to the branch (`git push origin my-new-feature`)
5. Create new Pull Request
## Credits
[](http://www.sticksnleaves.com)
Soulless is maintained and funded by [Sticksnleaves](http://www.sticksnleaves.com)
Thanks to all of our [contributors](https://github.com/anthonator/soulless/graphs/contributors)