(Rails5) Use Scoped Uniqueness Validations
Consider this: we have an aggregation app, that receives data from other apps.
class Event < ApplicationRecord
# Scheme
# t.integer :origin_app, null: false, default: 0, index: true
# t.integer :origin_type, null: false, default: 0, index: true
# t.integer :origin_id, null: false, index: true
enum origin_app: { old_app: 0, new_app: 1 }
enum origin_type: { good: 0, bad: 1 }
validates :origin_app, :origin_type, :origin_id, presence: true
end
We want to validate :origin_id
uniqueness within an app and type.
1. DB Level
Add a compound uniqueness index in migration.
# add_index :<table>, [:<validatable field>, :<scope_field_1>, .. , :<scope_field_n>], unique: true
# e.g.
add_index :admin_events, [:origin_id, :origin_app, :origin_type], unique: true
# NB, sometimes these compound indice names can get too long, use
add_index :admin_events, [:origin_id, :origin_app, :origin_type], unique: true, name: "idx_admin_event_origin_origin_app_origin_type"
# The logic would be:
# index becomes idx
# singular table name
# no joining words
# no _id
# alphabetical order
2. App Level
Add a uniqueness validation with scope option.
class Event < ApplicationRecord
# ...
validates :origin_id, uniqueness: {scope: [:origin_app, :origin_type]}
end
Troubleshooting
Consult the docs.
Written on May 26, 2016