Carrying out Rails challenges. We have decided to implement the follow function of User
.
I've implemented this feature before, and I remembered it as ** "I'm sure that association is difficult" **.
I happened to have the opportunity to teach people how to implement this feature, so I decided to write down the steps in detail so that I could teach them well.
However, since it has become quite a long sentence, it is divided into two parts. In this article, we will talk about DB design to association, and the continuation will be the following article.
Implement user follow function in Rails (I use Ajax) ②
The execution environment is as follows.
Rails 5.2.3
Ruby 2.6.0
What we will make this time is a user follow function. You can follow the user by pressing the button and unfollow by pressing the button again.
In addition, the model created for this function is as follows.
It's too mysterious, isn't it: sweat_smile: Suddenly, it is difficult to reach the above model, so I will disassemble it one by one.
In addition, the following is just ** "I thought this way" ** way of thinking, so depending on the person, other ways of thinking may be more suitable.
First of all, it is easier to understand if you create characters "user" and "follower", so
Explode the User
model into ** (in your head) ** User
and Follower
models.
Let's start with the situation where ** User, who seems to be the easiest, is following a lot of people **.
In this case, for the User
model
has_many: followings, through: :relationships
** Temporarily place the association ** (in my head) **. But keep in mind that ** User model = Follower model **.
The above relationship can be expressed in a migration file as follows.
db/migrate/XXXXXXXX_create_relationships.rb
class CreateRelationships < ActiveRecord::Migration[5.2]
def change
create_table :relationships do |t|
t.references :user
t.references :follower, foreign_key: { to_table: :users }
t.timestamps
t.index [:user_id, :follower_id], unique: true
end
end
end
The followers
table doesn't really exist, so I told Rails withforeign_key: {to_table :: users}
" Look at the users table (follower_id) when looking for followers " I will.
The implementation around here is ↓ This article was very helpful.
Also, don't follow the same person twice
t.index [:user_id, :follow_id], unique: true
The combination of the user_id
column and the follower_id
column is constrained to prevent duplicate values.
At this time, the description of the association of the User
model is as follows.
models/user.rb
class User < ApplicationRecord
has_many :relationships, dependent: :destroy
has_many :followings, through: :relationships, source: :follower
end
The points are as follows.
--In has_many: following
, add alias to association
--Tell Rails to look at the follower
model with source:: follower
It's getting a little complicated ...: frowning2: I've also posted links where it seems difficult, so please read them one by one.
By the way, how do you refer to the Follower
model when there is no Follower
model? ?? See the following Relationship
model associations for more information.
The contents of the Relationship
model are as follows.
models/relationship.rb
class Relationship < ApplicationRecord
belongs_to :follower, class_name: 'User'
end
By writing like this, Rails is told to refer to the User
model when the Follower
model is referenced.
source
and class_name
By the way, I referred to another model in source
earlier, but now why is it class_name
? Didn't you think? (I thought)
The reason is written here Rails: difference between :source => ?? and :class_name => ?? in models
-** source ** ... Used when has_many: ****, through:: ****
-** class_name ** ... Used when has_many: ***
That's right: smile: I didn't know! !!
At this point, it is advisable to make sure that the association is properly defined once. I confirmed it like this.
$ rails c
> user = User.first
> user.relationships
# => []
> user.relationships.create!(follower_id: 2)
# =>Relationship records are displayed
> user.followings
# =>User you are following(user_User with id 2)Record is displayed
Since the record of the user being followed is called, it can be said that the user with id: 1
can follow the user with id: 2
.
Now then, I would like to consider the opposite situation, in which ** users are followed by many followers **.
First of all, the goal is ** It would be nice if we could define the opposite arrow. ** ** I will write it in the figure concretely.
You'll end up with a diagram like this where follower
has a lot of users
through relationships
.
But the ** Follower model didn't really exist, it was equal to the User model **. Therefore, ** Let's rewrite the subject to User. ** **
User
has a lot of followers
through relationships
.
It's easy to understand in words, but this time, the Follow
model I made in my head got in the way.
I've put the followers
table together, which makes it harder to think about, so I've combined the Follow
and User
models into one.
It's pretty close to the ER diagram I presented at the beginning: grin:
By the way, I also tried to revive the red arrow.
Then, in the part of ** through:: relationships
, you can see that the name is duplicated **.
So, this time, I changed the name of one and named it passive_relationships
in the sense that user
is followed by follower
.
This is the same as the ER diagram presented at the beginning: relaxed:
Now, let's actually represent this relationship in a model.
First, the User
model looks like this:
models/user.rb
class User < ApplicationRecord
has_many :relationships, dependent: :destroy
has_many :followings, through: :relationships, source: :follower
has_many :passive_relationships, class_name: 'Relationship', foreign_key: 'follower_id', dependent: :destroy #Addendum 1
has_many :followers, through: :passive_relationships, source: :user #Addendum 2
end
It's getting really complicated: joy: As I read each one, the first part of Addendum 1 is
--User
has a lot of passive_relationships
.
--At this time, the class you want to refer to is Relationship
.
--Use follower_id
as a foreign key.
It represents that. Next, the part of postscript 2 is
--User
has a lot of followers
through passive_relationships
.
--passive_relationships
refers toRelationship and
classes by the previous definition.
It's too complicated to be indignant: joy: I intended to write it step by step, so please read it carefully: sweat_smile:
Finally, I would like to introduce the contents added to the Relationship
model.
models/relationship.rb
class Relationship < ApplicationRecord
belongs_to :user #Postscript
belongs_to :follower, class_name: 'User'
end
On the contrary, this is too simple and worrisome, but this is the end: innocent:
Here, let's check once. Earlier, I created the data that ** id: 1 user follows id: 2 user ** on the console, so ** id: 2 user is being followed by id: 1 user. **must.
Try it on the console.
$ rails c
> user2 = User.second
> user2.followers
# => id:1 User record is displayed
I got the user who is following user2! !! Success: smile:
to be contenued ... From now on, view and controller will be implemented! ... but From here, I will continue next time.
Ajax doesn't come out! If you think, I'm sorry. Will come out next time. .. ..
▼ Click here for the sequel to this story Implement user follow function in Rails (I use Ajax) ②
Recommended Posts