active-model
Version, currently 4.1.040 versions
- 4.5.0latestAug 12, 2026
- 4.4.2not indexedAug 12, 2026
- 4.4.1not indexedAug 12, 2026
- 4.4.0not indexedAug 12, 2026
- 4.3.3not indexedAug 12, 2026
- 4.3.2not indexedAug 12, 2026
- 4.3.1not indexedAug 12, 2026
- 4.3.0not indexedAug 12, 2026
- 4.2.3not indexedAug 12, 2026
- 4.2.2not indexedAug 12, 2026
- 4.2.1not indexedAug 12, 2026
- 4.2.0not indexedAug 12, 2026
- 4.1.0not indexedAug 12, 2026
- 4.0.0not indexedAug 12, 2026
- 3.1.1not indexedAug 12, 2026
- 3.1.0not indexedAug 12, 2026
- 3.0.0not indexedAug 12, 2026
- 2.0.5not indexedAug 12, 2026
- 2.0.4not indexedAug 12, 2026
- 2.0.3not indexedAug 12, 2026
- 2.0.2not indexedAug 12, 2026
- 2.0.1not indexedAug 12, 2026
- 2.0.0not indexedAug 12, 2026
- 1.8.4not indexedAug 12, 2026
- 1.8.3not indexedAug 12, 2026
- 1.8.2not indexedAug 12, 2026
- 1.8.1not indexedAug 12, 2026
- 1.7.0not indexedAug 12, 2026
- 1.6.0not indexedAug 12, 2026
- 1.5.0not indexedAug 12, 2026
- 1.4.3not indexedAug 12, 2026
- 1.4.2not indexedAug 12, 2026
- 1.4.1not indexedAug 12, 2026
- 1.4.0not indexedAug 12, 2026
- 1.3.0not indexedAug 12, 2026
- 1.2.0not indexedAug 12, 2026
- 1.1.0not indexedAug 12, 2026
- 1.0.1not indexedAug 12, 2026
- 1.0.0not indexedAug 12, 2026
- 0.1.0not indexedAug 12, 2026
github.com/spider-gazelle/active-model
A rails-esque model framework for crystal lang
28 stars
1 dependent
License: MIT
Nothing has been indexed for 4.1.0 yet. The tag is recorded, its shard.yml has not been read, so the manifest and dependency list below are empty because they are unknown rather than because they are absent.
Installation
# Add this to your shard.yml
dependencies:
active-model:
github: spider-gazelle/active-model
version: ~> 4.1.0Then run:
shards installshard.yml
No shard.yml has been indexed for 4.1.0. You can read it on the repository.
Dependencies
Unknown: the shard.yml for this version has not been read yet.
README
This README is the one indexed from the repository at its latest ref, not from the tag for this version.
# Spider-Gazelle ActiveModel
[](https://github.com/spider-gazelle/active-model/actions/workflows/CI.yml)
[](https://crystal-lang.org/api/1.0.0/)
Active Model provides a known set of interfaces for usage in model classes. Active Model also helps with building custom ORMs.
## Usage
Please also checkout the [detailed guide](https://spider-gazelle.net/#/models/basics).
### Active Model
ActiveModel::Model should be used as the base class for your ORM
```crystal
require "active-model"
class Person < ActiveModel::Model
attribute name : String = "default value"
attribute age : Int32
end
p = Person.from_json("\"name\": \"Bob Jane\"")
p.name # => "Bob Jane"
p.to_json # => "\"name\":\"Bob Jane\""
p.attributes # => {:name => "Bob Jane", :age => nil}
p.age = 32
p.attributes # => {:name => "Bob Jane", :age => 32}
```
The `attribute` macro takes two parameters. The field name with type and an optional default value.
You can also define enum attributes!<br>
The default serialisation for enums is to a downcased string. Use [`Enum::ValueConverter(T)`](https://crystal-lang.org/api/latest/Enum/ValueConverter.html) if you want to serialise to the value backing members of the enum.
```crystal
require "active-model"
class Order < ActiveModel::Model
enum Product
Fries
Burger
end
enum Size
Medium
ExtraMedium
end
attribute product : Product = Product::Fries
attribute size : Size = Size::ExtraMedium, converter: Enum::ValueConverter(Size)
end
```
#### Validations
ActiveModel::Validators is a mix-in that you include in your class. Similar to those supported by Rails: <http://guides.rubyonrails.org/active_record_validations.html>
```crystal
require "active-model"
class Person < ActiveModel::Model
include ActiveModel::Validation
attribute name : String
attribute age : Int32
validates :name, presence: true, length: { minimum: 3 }
validates :age, presence: true, numericality: {greater_than: 5}
end
```
The `validate` macro takes three parameters. The symbol of the field and the message that will display when the validation fails. The third is a `Proc` that is provided an instance of `self` and returns either true or false.
To check to see if your instance is valid, call `valid?`. Each Proc will be called and if any of them fails, an `errors` Array with the messages is returned.
If no Symbol is provided as a first parameter, the errors will be added to the `:base` field.
```crystal
person = Person.new(name: "JD")
person.valid?.should eq false
person.errors[0].to_s.should eq "Name is too short"
```
#### Dirty Checking
Changes to attributes are tracked throughout the lifetime of the model. Similar to Rails: <http://api.rubyonrails.org/classes/ActiveModel/Dirty.html>
```crystal
person = Person.new(name: "JD")
person.changed? # => true
person.changed_attributes # => {:name => "JD"}
person.name_changed? # => true
person.name_change # => {nil, "JD"}
person.name_was # => nil
person.clear_changes_information
person.changed? # => false
```
#### Callbacks
Register before/after callbacks for `create`, `update`, `delete`, `save` methods. You must define the method you wish to register callbacks for.<br>
Registered callbacks are invoked through wrapping crud logic with the `run_create_callbacks`, `run_update_callbacks`, etc. functions
```crystal
require "active-model"
class Person < ActiveModel::Model
include ActiveModel::Callbacks
attribute name : String
attribute age : Int32
before_save :capitalize
def capitalize
@name = @name.capitalize
end
def save
run_save_callbacks do
# save to database
@foo.save(attributes)
end
end
end
```
#### Serialization
The `serialization_group` argument to `attribute` accepts an `Array(Symbol)` or `Symbol`.
This will include the attribute in a generated serializer, `#to_<group>_json`.
The `define_to_json` macro allows for defining subset serializations via `only` and `except` arguments. The `methods` argument allows for inclusion of instance methods in the serializer.
```crystal
require "active-model"
class SerializationGroups < ActiveModel::Model
attribute everywhere : String = "hi", serialization_group: [:admin, :user, :public]
attribute joined : Int64 = 0, serialization_group: [:admin, :user]
attribute mates : Int64 = 0, serialization_group: :user
attribute another : String = "ok"
define_to_json :some, only: [:joined, :another]
define_to_json :most, except: :everywhere
define_to_json :method, only: :joined, methods: :foo
getter foo = "foo"
end
m = SerializationGroups.new
m.to_public_json # {"everywhere":"hi"}
m.to_admin_json # {"everywhere":"hi","joined":0}
m.to_user_json # {"everywhere":"hi","joined":0,"mates":1}
m.to_some_json # {"joined":0,"another":"ok"}
m.to_most_json # {"joined":0,"mates":0,"another":"ok"}
m.to_method_json # {"joined":0,"foo":"foo"}
```
#### Sanitization
Use the `sanitize:` option on `attribute` to automatically strip or clean HTML content from string fields and from arbitrarily-nested containers of strings.
Sanitization is applied on every write path — constructors, setters, JSON/YAML deserialization, and HTTP params.
Supported policies:
| Policy | Behaviour |
|--------|-----------|
| `:text` | Strips **all** HTML tags, returning plain text |
| `:basic` | Allows basic formatting (`<b>`, `<i>`, etc.) |
| `:inline` | Allows inline elements, strips block-level elements |
| `:common` | Allows common safe HTML (`<p>`, `<b>`, `<i>`, etc.) |
Supported field types (each may also be wrapped in `?` to make it nilable):
| Type | Behaviour |
|------|-----------|
| `String` | Sanitize the value |
| `JSON::Any` | Walk the tree; sanitize string leaves only. Non-string scalars (numbers, booleans, nulls) and object keys pass through |
| `Array(T)` | Sanitize each element; length and order are preserved |
| `Set(T)` | Sanitize each element; the set may shrink if two values collapse to the same sanitized string. Use `Array(T)` if order/length matter |
| `Hash(K, V)` | Sanitize each value; keys are left untouched (`K` can be any type) |
| `Union` (e.g. `String \| Int32`) | At least one arm must be sanitizable; non-sanitizable arms pass through at runtime |
Element types inside containers can themselves be any sanitizable type, so `Array(Hash(String, Array(String)))` is supported.
```/dev/null/example.cr#L1-18
require "active-model"
class Article < ActiveModel::Model
attribute title : String, sanitize: :text
attribute body : String?, sanitize: :common
attribute tags : Array(String), sanitize: :text
attribute keywords : Set(String), sanitize: :text
attribute metadata : Hash(String, String), sanitize: :common
end
article = Article.new(title: "<b>Hello</b> World", tags: ["<b>one</b>", "<i>two</i>"])
article.title # => "Hello World"
article.tags # => ["one", "two"]
article.body = "<p>Safe</p><script>alert('xss')</script>"
article.body # => "<p>Safe</p>"
```
The `sanitize:` option is only valid for the field types listed above. Attempting to use it on a type with no sanitizable leaves (e.g. `Int32`, `Array(Int32)`, `Hash(String, Int32)`) produces a compile-time error.
##### Custom and rare types
For types not in the built-in list — your own classes, or stdlib types like `Tuple`, `NamedTuple`, `Deque`, `Range` — opt in by defining a wrapper that includes `ActiveModel::Sanitizable` and implements `sanitize(policy : Symbol) : self`. The macro walker accepts any type that includes the module, and the runtime delegates to the type's own `sanitize` method:
```/dev/null/sanitizable.cr#L1-14
class Address
include ActiveModel::Sanitizable
property street : String
property city : String
def initialize(@street : String, @city : String); end
def sanitize(policy : Symbol) : self
@street = ActiveModel::Sanitizer.sanitize(@street, policy)
@city = ActiveModel::Sanitizer.sanitize(@city, policy)
self
end
end
class Order < ActiveModel::Model
attribute address : Address, sanitize: :text
attribute addresses : Array(Address), sanitize: :text # nesting works
end
```
For stdlib generic types (`Tuple`, `Range`, etc.), prefer wrapping in a `Sanitizable` struct rather than reopening the stdlib type — reopening makes every instance globally satisfy `is_a?(Sanitizable)` and demand the abstract method.
`JSON::Any` is also a universal fallback: any unusual JSON-shaped payload can be modelled as `JSON::Any` and sanitized.
Documentation
Built from the current release. The first visit to a release nobody has asked for starts its build.
Links
This release
- Version
4.1.0- Tagged
- Aug 12, 2026
- Commit
2a6543434d44- Indexed
- not yet
Dependents
Repository
github.com/spider-gazelle/active-model
Metadata
- Created
- Aug 12, 2026
- Updated
- Aug 12, 2026
- Synced
- Aug 12, 2026
- Versions
- 40