Defaulter allows you to mark and maintain default objects in ActiveRecord association collections with minimal code and minimal fuss.
For example, a User
model can have many Email
models using ActiveRecords has_many
functionality. But which email address do you send mail to? Certainly not all, that's just irritating. Instead, marking a particular record as default and sending mail there is a much better idea. The defaulter gem allows you to achieve that rather simply.
Besides Rails 4 beta, defaulter now supports Rails 3.2. It may work on lower rails versions, but your mileage may vary.
Put this in your project's Gemfile:
gem 'defaulter'
Don't forget to run the bundle
command to fetch the gem.
Next, you'll need to add one column to whichever table where you want to mark default records. Since both default
and primary
are reserved words in SQL, we go with the name prime
. If you're making a migration afresh, tuck the following line in your migration's create_table
call:
t.boolean :prime, null: false, default: false
If already have a migration, you will need to create a new one and add the column like so:
add_column :table_name, :prime, null: false, default: false
Now, run the migrations.
NOTE: Adding proper indexes will speed-up your finds.
There's no Step 3. We're ready to roll.
The defaulter gem gives you a has_default
call that sets up the model and the has_many
association automatically for you. Going with our User
and Email
example, a user can have many emails, one of which may be a default record. The User
class can look like so:
class User < ActiveRecord::Base
has_default :email
end
NOTE: There is no need to add has_many :emails
, has_default :email
does that for you automatically. Also all of the has_many
options, including polymorphism are supported.
The Email
class can go unchanged:
class Email < ActiveRecord::Base
belongs_to :user
end
Usage is surprisingly simple. Defaulter extends ActiveRecord for getting and setting a default record like so.
If you've followed along carefully, user.emails
should get you all the email addresses; and, user.emails.default
should get you the default email address.
To set a new default email, user.emails.default = user.emails.last
will set a new default email address. The older default record will now longer be the default.
NOTE: The new default record will have to exist in the collection before you can set it as a new default.
Defaulter overides ActiveRecord's <<
so that a new record or collections can be added. If the new record is marked as default by setting prime
to true
, the existing default record will cease to be one. If a collection has more than one item marked as default, the last item will take precendence. In short, defaulter will do eveything it can to ensure that there is just one default record on the database for an association collection at any given time.
I threw this gem together in about half an hour, there is scope for improvement. I will appreciate contributions in the following areas:
- Tests, Tests, Tests
- Ability the configure the name of the default column, by passing it with the
has_default
call like so:has_default :email, default_column: :primordial
- Dynamically generated utitlity instance methods like
default_email
anddefault_address
- Optionally, prevent default records from being destroyed
Backport to Rails 3.2(v0.0.9)
MIT License. Copyright © 2013 Amol Hatwar.