The simplest way to handle the primary or default flag to your Rails models.
- Supports single model (without association), model with (
belongs_to) association, and even polymorphic associations
- Force primary
- Supports PostgreSQL's unique partial index (constraint)
- Supports PostgreSQL, MySQL, and SQLite
Add this line to your application's Gemfile:
And then execute:
Or install it yourself as:
$ gem install set_as_primary
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.
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.
set_as_primary class helper method, pass your primary flag attribute. You might need to pass
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
make sure that flag should be present in the table and should be a boolean data type column.
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
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.
class Address < ApplicationRecord include SetAsPrimary belongs_to :user set_as_primary :default, owner_key: :user, force_primary: false end
force_primary option is set to
true. If this option is
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
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.
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.
The gem is available as open source under the terms of the MIT License.