ActionState provides a simple DSL for defining Rails model states allowing you to query the state as an ActiveRecord scope on the class and a predicate on the instance.
For example, the following state definition defines a class scope Article.published
and an instance predicate article.published?
.
class Article < ApplicationRecord
state(:published) { where(published_at: ..Time.current) }
...
end
If you’re interested in contributing to this project, you can book a pairing session with me and we can work through it together and I can hopefully share some context with you. Otherwise, please feel free top open a PR / issue / description. ❤️
ActionState supports a small subset of ActiveRecord queries for the predicate definition, and delegates the scope definition to ActiveRecord.
It's not meant to comprehensively support every possible ActiveRecord query; rather it supports a few features that tend to lend themselves well to predicate definitions.
The where
method checks for inclusion in an Enumerable, coverage by a Range, and equality with other types of value.
state(:crafter) { where(role: ["designer", "developer"]) }
state(:negative) { where(stars: 1..4 }
state(:indifferent) { where(stars: 5..6) }
state(:positive) { where(stars: 7..9) }
state(:recently_published) { where(published_at: 1.week.ago..) }
state(:featured) { where(featured: true) }
The counterpart to where
is where.not
which checks for exclusion from an Enumerable or Range, and inequality with other types of value.
state(:deleted) { where.not(deleted_at: nil) }
The excluding
method excludes specific instances of a model.
state(:normal) { excluding(special_post) }
States can also be defined to accept arguments.
state(:before) { |whenever| where(created_at: ..whenever) }
state(:after) { |whenever| where(created_at: whenever..) }
You can chain query methods together to form more complex queries.
state(:can_edit) { where(role: "admin").where.not(disabled: true) }
You can also compose multiple states together.
state(:published) { where(published: true) }
state(:featured) { published.where(featured: true) }
Add this line to your application's Gemfile:
gem "action_state"
And then execute:
$ bundle
Or install it yourself as:
$ gem install action_state
Finally, include ActionState
in your model class or ApplicationRecord
:
class ApplicationRecord < ActiveRecord::Base
include ActionState
...
end
The gem is available as open source under the terms of the MIT License.