SetAsPrimary
The simplest way to handle primary or default boolean flag to your Rails model records.
Features:
- Supports single model (without association), model with (
belongs_to
) association, and even polymorphic associations - Force primary
- Supports PostgreSQL, MySQL, and SQLite
- Supports PostgreSQL's unique partial index (constraint)
You can find source code of demo Rails application here.
A lovely quote from a user ❤️
Thanks for this gem!
This gem solves a small, relatively obscure need but it does so really, really well. Thank you!
Installation
Add this line to your application's Gemfile:
gem 'set_as_primary'
And then execute:
$ bundle
Or install it yourself as:
$ gem install set_as_primary
Usage
In your Rails application, you might have models like EmailAddress, PhoneNumber, Address, etc., which belong to the User/Person model or polymorphic model. There, you might need to set a primary email address, primary phone number, or default address for a user, and this gem helps you to do that.
It also supports a single model with no association context.
Examples:
class User < ApplicationRecord
has_many :email_addresses
has_many :addresses, as: :owner
end
class EmailAddress < ApplicationRecord
include SetAsPrimary
belongs_to :user
set_as_primary :primary, owner_key: :user
end
class Address < ApplicationRecord
include SetAsPrimary
belongs_to :owner, polymorphic: true
set_as_primary :primary, owner_key: :owner
end
# Single model with no owner/association context.
class Post < ApplicationRecord
include SetAsPrimary
set_as_primary :primary
end
You need to include SetAsPrimary
module in your model where you want to handle the primary flag.
Then to set_as_primary
class helper method, pass your primary flag attribute. You might need to pass
association key owner_key
if you want to consider owner (association) context.
Note: Default primary flag attribute is primary
, and you can use another one too like default
but
make sure that flag should be present in the table and should be a boolean data type column.
Migration
If your table does not have the primary flag column, then you can add it by running following command in your rails project:
rails generate set_as_primary your_table_name flag_name
Example:
If you want to add a primary
column to your posts
table, then you can run command like this:
rails generate set_as_primary posts primary
Then migration gets created like this:
class AddPrimaryColumnToPosts < ActiveRecord::Migration[6.0]
def change
add_column :posts, :primary, :boolean, default: false, null: false
# NOTE: Please uncomment following line if you want only one 'true' (constraint) in the table.
# add_index :posts, :primary, unique: true, where: "(posts.primary IS TRUE)"
end
end
If you want to create a primary column to email_addresses
table, then you can run command like this:
rails generate set_as_primary email_addresses primary user
Then it creates migration like this:
class AddPrimaryColumnToEmailAddresses < ActiveRecord::Migration[6.0]
def change
add_column :email_addresses, :primary, :boolean, default: false, null: false
# NOTE: Please uncomment following line if you want only one 'true' (constraint) in the table.
# add_index :email_addresses, %i[user_id primary], unique: true, where: "(email_addresses.primary IS TRUE)"
end
end
You might have seen extra commented lines there. These lines are there for handling the unique constraint. Currently, these lines get created only for PostgreSQL
adapter as it supports partial index.
Please note that here we have passed an extra option user
in the command that is nothing but the owner/association name. This extra option helps to handle the unique partial index.
Note: Partial indexes are only supported for PostgreSQL and SQLite 3.8.0+. But I also found that SQLite gives an error so currently this gem only supports PostgreSQL's unique partial index constraint.
Even if we don't have constraint (only one 'true' constraint in the table), this gem takes care of it so don't worry about the constraint.
Once migration file gets created, don't forget to run rails db:migrate
to create an actual column in the table.
force_primary
class Address < ApplicationRecord
include SetAsPrimary
belongs_to :user
set_as_primary :default, owner_key: :user, force_primary: false
end
By default force_primary
option is set to true
. If this option is true
,
then it automatically sets record as primary when there is only one record in
the table. If you don't want this flow, then set it as false
.
Development
After checking out the repo, run bin/setup
to install dependencies. Then, run
rake test
to run the tests. You can also run bin/console
for an interactive
prompt that will allow you to experiment.
Contributing
Bug reports and pull requests are welcome on GitHub at https://github.com/mechanicles/set_as_primary. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the Contributor Covenant code of conduct.
License
The gem is available as open source under the terms of the MIT License.