Like Twitter, one user can like multiple tweets, and one tweet likes multiple users. I think we often implement many-to-many relationships such as! The combination must be unique because some users like only once per tweet. This time, I will explain how to make the combination of data in the intermediate table unique.
Rails 6.0.3 Ruby 2.7.1 Tests: Rspec, FactoryBot, shoulda-matchers
The following three tables are used this time.
id | name | |
---|---|---|
1 | User 1 | [email protected] |
2 | User 2 | [email protected] |
id | content |
---|---|
1 | tweet1 |
2 | tweet2 |
id | user_id | tweet_id |
---|---|---|
1 | 1 | 2 |
2 | 1 | 3 |
I will omit the many-to-many explanation this time.
user.rb
class User < ApplicationRecord
has_many :likes, dependent: :destroy
end
tweet.rb
class Tweet < ApplicationRecord
has_many_to :likes
end
like.rb
class Like < ApplicationRecord
belongs_to :user
belongs_to :tweet
end
And it is implemented in the main this time. There are two things to do.
Add ʻadd_index: likes, [: user_id,: tweet_id], unique: true` to the migration file of the intermediate table. Don't forget to migrate after adding!
class CreateLikes < ActiveRecord::Migration[6.0]
def change
create_table :likes do |t|
t.references :user, null: false, foreign_key: true
t.references :tweet, null: false, foreign_key: true
t.timestamps
end
add_index :likes, [:user_id, :tweet_id], unique: true #Add here
end
end
Add validates: hotel_id, uniqueness: {scope:: staff_id}
to the intermediate table model.
like.rb
class Like < ApplicationRecord
belongs_to :user
belongs_to :tweet
validates :user_id, uniqueness: { scope: :tweet_id } #Add here
end
That's all the required implementation. Make sure you can only register the same combination once in the console.
For reference, we will also introduce the test. It is assumed that Rspec, FactoryBot, and shoulda-matchers have been set.
like_spec.rb
require 'rails_helper'
RSpec.describe Like, type: :model do
let(:user) { create(:user) }
let(:tweet) { create(:tweet) }
before { create(:like, user: user, tweet: tweet) }
it { should belong_to(:user) } #Check the many-to-many relationship between this line and the line below
it { should belong_to(:tweet) }
it { is_expected.to validate_uniqueness_of(:user_id).scoped_to(:tweet_id) } #Make sure it is unique here
end
Did you make the combination unique? I think that implementations like this one are often used, so I hope you find it helpful.
Recommended Posts