Reputation: 2900
I've got Rating
model to evaluate my features by user. When user click like or dislike button under one of my feature (e.g. data_chart
) the new Rating record should be created. Example rating record: #<Rating:0x00007f8d839b2630 id: 7, customer_id: 1, actions: 'like', feature_uid: data_chart>
. I want to prevent situation like below:
#<Rating:0x00007f8d839b2630 id: 7, customer_id: 1, actions: 'like', feature_uid: 'data_chart'>
#<Rating:0x00007f8d839b2630 id: 8, customer_id: 1, actions: 'dislike', feature_uid: 'data_chart'>
As you see there are two records for the same customer and for the same feature_uid
. I want to prevent such scenarios since customers can evaluate each feature only once, without ability to change.
Code below:
def change
create_table :ratings do |t|
t.references :customer, null: false, foreign_key: true
t.string :action, null: false
t.string :feature_uid, null: false
t.timestamps
end
end
class Rating < ApplicationRecord
belongs_to :customer
validates :feature_uid, inclusion: { in: ['data_chart (...) some_other_features)'] }
validates :action, inclusion: { in: %w[like dislike] }
end
Upvotes: 1
Views: 1118
Reputation: 9228
You can prevent the creation of new records for already existing customer_id
and feature_uid
pairs using the uniqueness
validator.
In your particular case it will look like the following:
class Rating < ApplicationRecord
belongs_to :customer
# ...
validates :feature_uid, uniqueness: { scope: :customer_id }
end
Here is a link to the official docs.
It is also worth mentioning that the uniqueness validator works only on the model level, in other words, it does not create a uniqueness constraint in the database, so it may happen that two different simultaneous database connections create two records with the same values for columns that you intend to be unique.
In order to prevent such cases, you need to create a unique index on the pair of columns in your database. For instance, see the MySQL manual for more details about multiple column indexes or the PostgreSQL manual for examples of unique constraints that refer to a group of columns.
Here is a way how to create a unique index on multiple columns using Rails migrations.
$ rails generate migration add_unique_index_for_customer_id_and_feature_uid_to_ratings
class AddUniqueIndexForCustomerIdAndFeatureUidToRatings < ActiveRecord::Migration[6.1]
def change
add_index(:ratings, [:customer_id, :feature_uid], unique: true)
end
end
$ rails db:migrate
Upvotes: 1