Implement user follow function in Rails (I use Ajax) ①

What did you do

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.

goal

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.

Image from Gyazo

In addition, the model created for this function is as follows.

Image from Gyazo

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.

Implementation

Disassemble and think

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.

Image from Gyazo

Let's start with the situation where ** User, who seems to be the easiest, is following a lot of people **.

Image from Gyazo 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.

How to specify a column whose reference table name cannot be estimated automatically as a foreign key in migration

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.

Description of association

Users model

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.

Relationship model

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.

Digression: About the difference between 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! !!

Verification

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.

Consider the opposite relationship

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.

Image from Gyazo

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. ** **

Image from Gyazo

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.

Image from Gyazo

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 **.

Image from Gyazo

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:

Description of association

User model

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:

Relarionship model

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:

Verification

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

Implement user follow function in Rails (I use Ajax) ②
Implement user follow function in Rails (I use Ajax) ①
Implement follow function in Rails
Implemented follow function in Rails (Ajax communication)
I tried to implement Ajax processing of like function in Rails
Implement application function in Rails
[Rails] Implement User search function
Implement simple login function in Rails
Implement CSV download function in Rails
Implement user registration function and corporate registration function separately in Rails devise
Rails follow function
[Rails 6] Asynchronous (Ajax) follow function is implemented
Use [Rails] devise Guest user function (for portfolio)
Implement star rating function using Raty in Rails6
Implement the Like feature in Ajax with Rails.
How to make a follow function in Rails
Follow function (Ajax) implementation
[Rails] Implement search function
Use images in Rails
Implement markdown in Rails
[Rails / JavaScript / Ajax] I tried to create a like function in two ways.
How to implement a like feature in Ajax in Rails
[Rails] Implement credit card registration / deletion function in PAY.JP
Introduce devise in Rails to implement user management functionality
I want to use a little icon in Rails
I want to define a function in Rails Console
Implement LTI authentication in Rails
[Rails] (Supplement) Implemented follow function
Implement import process in Rails
Ajax bookmark function using Rails
Use multiple checkboxes in Rails6!
[Rails] Implement image posting function
Implement login function in Rails simply by name and password (1)
Implement login function in Rails simply by name and password (2)
Implement login function simply with name and password in Rails (3)
[Rails] I tried to implement "Like function" using rails and js
Use voice recognition function in Unity
[Rails] A simple way to implement a self-introduction function in your profile
[Implementation procedure] Create a user authentication function using sorcery in Rails
[Rails] Implementation of user withdrawal function
I tried to implement the image preview function with Rails / jQuery
[Rails] Use cookies in API mode
Implement tagging function in form object
Implement a contact form in Rails
Implement star evaluation function in Rails 6 (Webpacker is installed as standard)
[Rails] I will explain the implementation procedure of the follow function using form_with.
[Rails] Use devise to get information about the currently logged in user
"Teacher, I want to implement a login function in Spring" ① Hello World
How to implement search functionality in Rails
[Rails] Function restrictions in devise (login / logout)
How to use custom helpers in rails
[Ruby on Rails] Follow function implementation: Bidirectional
How to implement ranking functionality in Rails
I want to use @Autowired in Servlet
How to use credentials.yml.enc introduced in Rails 5.2
Implement button transitions using link_to in Rails
How to implement image posting function using Active Storage in Ruby on Rails
Where I got stuck in today's "rails tutorial" (2020/10/08)
[Rails] When I use form_with, the screen freezes! ??
Implement share button in Rails 6 without using Gem
I tried to implement polymorphic related in Nogizaka.