I started reading ahead into ActiveRecord…whoa…that’s some crazy stuff
right there. Mind was blown with the sprawling nature of it…so many avenues
and byways of logic, it’s going to take some serious time to get to the bottom
of that. In the mean time, let’s jump into ActiveModel in earnest.
Getting Started with ActiveModel::Model
ActiveModel has a lot of things going on too, but it’s easy to see how they
build on one another, so let’s start with ActiveModel::Model
Really easy. But, how does it do this and what other features do we get via this one include? Here is the source for model.rb:
Looking at the code above should make it super easy to see how the Coffee.new works: we iterate over the implied hash of attributes and call public_send on the setter method provided via attr_accessor.
Invokes the method identified by symbol, passing it any arguments specified. Unlike send, public_send calls public methods only.
This module gives our class some methods which are very handy for routing and the naming of database tables, stuff like route_key and singular_route_key, all through the magic of ActiveSupport’s Inflector. Take a peek:
So for instance:
This is a minor interface for Rails’ i18n implementation that basically leverages Naming for the purpose of translating your object’s name into other localities. It has some savviness for scopes and ancestors, but I’m going to skip it.
Very small piece of code that handles some to_param and to_model methods. Skipping.
You already know what this is going to provide:
So how does it work? Well, ActiveModel::Validations stripped down to the basics looks like:
Of course, there is a whole directory of specific validations and additional logic underneath this one, but for now let’s focus on the bones.
When we include Validations, it pulls in ActiveModel::Callbacks and defines a callback for validation. It also creates a nifty _validators hash with a specific constructor block. If you haven’t used an initialization block on your Hashes yet, check it out:
Ok, so we have a callback added to our model as well as a hash keyed on model attribute with an array of validators. Callbacks are very complicated (and very cool), but we can take a glimpse via knowing how define_callbacks works:
Looks like our model now has a before callback with a Proc being called. I’ll have to do a follow up post on the magic of Callbacks, but for now I’m sure you can guess what code is inside (our validation code).
So when do our validations get run? From the above we can see run_callbacks manually triggered whenever we call valid? but what wasn’t as obvious to me is that run_callbacks :validate is what triggers the callback procs generated via set_callback in validate(*args,&block).
we include ActiveModel::Model which includes ActiveModel::Validations
we specify a validates in our model which gets translated into a set_callback with the right trigger conditions (before, after, context)
valid? triggers the execution of all scoped callbacks in the right call order (fancy chains were made)
an ActiveModel::Errors object is populated which then provides the errors and messages as necessary
For curiousity’s sake, what runs the callbacks? This does!
Whoa, looks cool. Next time, we will dig into it…I know, ActiveSupport again, but it’s just so magical I can’t resist!