让任何 Ruby 对象都像 ActiveRecord 一样发出鸣叫
ActiveType is our take on "presenter models" (or "form models") in Rails. We want to have controllers (and forms) talk to models that are either not backed by a database table, or have additional functionality that should not be shared to the rest of the application.
However, we do not want to lose ActiveRecord's amenities, like validations, callbacks, etc.
Examples for use cases are models to support sign in:
class SignIn "User (...)"
# or
sign_up = SignUp.new
sign_up.class # => "SignUp (...)"
sign_up.class.extended_record_base_class # => "User (...)"If you want to inherit from an ActiveType class, simply do
class SignUp "kratob").nickname # "kratob"You can override attribute getters and setters using super:
class SignIn
You have to say nests_many :records
records will be validated and saved automatically
The generated .records_attributes = expects parameters like ActiveRecord's nested attributes, and works together with the fields_for helper:
either as a hash (where the keys are meaningless)
{
'1' => { date: "new record's date" },
'2' => { id: '3', date: "existing record's date" }
}or as an array
[
{ date: "new record's date" },
{ id: '3', date: "existing record's date" }
]To use it with single records, use nests_one. It works like accept_nested_attributes does for has_one. Use .record_attributes = to build the child record.
Supported options for nests_many / nests_one are:
build_scope
Used to build new records, for example:
nests_many :documents, build_scope: proc { Document.where(:state => "fresh") }find_scope
Used to find existing records (in order to update them).
scope
Sets find_scope and build_scope together.
If you don't supply a scope, ActiveType will guess from the association name, i.e. saying
nests_many :documentsis the same as saying
nests_many :documents, scope: proc { Document }which is identical to
nests_many :documents, build_scope: proc { Document }, find_scope: proc { Document }All ...scope options are evaled in the context of the record on first use, and cached.
allow_destroy
Allow to destroy records if the attributes contain _destroy => '1'
reject_if
Pass either a proc of the form proc { |attributes| ... }, or a symbol indicating a method, or :all_blank.
Will reject attributes for which the proc or the method returns true, or with only blank values (for :all_blank).
default
Initializes the association on first access with the given proc:
nests_many :documents, default: proc { Documents.all }Options supported exclusively by nests_many are:
index_errors
Use a boolean to get indexed errors on related records. In Rails 5 you can make it global with
config.active_record.index_nested_attribute_errors = true.
When working with ActiveType you will often find it useful to cast an ActiveRecord instance to its extended ActiveType::Record variant.
Use ActiveType.cast for this:
class User trueThis is basically like ActiveRecord#becomes, but with less bugs and more consistent behavior.
Note that cast is destructive. The originally casted record (user) and the returned record (sign_up)
share internal state (such as attributes). To avoid unexpected behavior, the original record will raise an error when trying to change or persist it. Also, casting of a record that has changes in its loaded associations is prevented, because those changes would be lost.
If you know what you are doing and absolutely want that, you may use the option force: true to allow this potentially problematic behaviour, e.g. sign_up = ActiveType.cast(user, SignUp, force: true)
You can also cast an entire relation (scope) to a relation of an ActiveType::Record:
adult_users = User.where('age >= 18')
adult_sign_ups = ActiveType.cast(adult_users, SignUp)
sign_up = adult_sign_ups.find(1)
sign_up.is_a?(SignUp) # => trueIf you need to add some special logic after casting you can add an after_cast method:
class SignUp bundle exec rspec spec`.
- When you make a pull request, tests are automatically run against all variants and Rubies on travis.ci.
If you would like to contribute:
- Fork the repository.
- Push your changes **with passing specs**.
- Send us a pull request.
I'm very eager to keep this gem lightweight and on topic. If you're unsure whether a change would make it into the gem, [talk to me beforehand](mailto:[email protected]).
Credits
-------
Tobias Kraze from [makandra](http://makandra.com/)
Henning Koch from [makandra](http://makandra.com/)暂无开放 Issues,或尚未同步最近议题。