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.3Ruby 2.6.0What 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_nameBy 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 andclasses 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