Make a matching app in Rails

Try to make matching function in Rails

I thought about making something related to Christmas, but I just went to this because I was poor in thinking and I only saw matching sites.

I introduce to the center of matching function.


Design

The design is arranged using bootstrap.

gem 'bootstrap-sass'
gem 'jquery-rails'

By default gem 'sass-rails', '~> 5.0' is included so install the above.

application.js
//= require jquery
//= require bootstrap-sprockets

Change. css to. scss and make the following description.

application.scss
@import "bootstrap-sprockets";
@import "bootstrap";


Now I will use bootstrap. Motivation will change much with design, so let me feel it like that.


##Following users

Match will be established if each other follows each other. To that end, I think that I will add a function to follow users first. User management is left to devise.

gem 'devise'
bundle install --path vendor/bundle
rails g devise:install
rails g devise:views
rails g devise user

I will implement many-to-many associations among the users I make. Let's create a model that keeps user relationships.

rails g model relationship
class CreateRelationships < ActiveRecord::Migration[5.1]
  def change
    create_table :relationships do |t|
      t.integer :follower_id
      t.integer :following_id
      t.timestamps
    end
    add_index :relationships, :follower_id
    add_index :relationships, :following_id
    add_index :relationships, [:follower_id, :following_id], unique: true
  end
end

Paste the index as well. association. For the time being we will only consider doing it.

###Make a like Form

I hope to have specifications to follow that user by pressing a like button. Like button will go to the user's show page.

users_controller.rb
class UsersController < ApplicationController

#abridgement
  def show
    @user = User.find(params[:id])
    @relationship = Relationship.new
  end
end
show.html.haml-users
.text-center
    = image_tag @user.avatar, class: "avatar"
.text-center#user-description
    = @user.nickname
    - if user_signed_in?
        #follow_form
            - if current_user.following?(@user)
                #liked.btn.btn-default liked
            - else
                = render 'follow', {relationship: @relationship}
    %br= @user.profile
User.rb
def following?(other_user)
  following.include?(other_user)
end
_folllow.html.haml
= form_with model: relationship, remote: true do |f|
    %div= hidden_field_tag :following_id, @user.id
    = f.submit "like", class: "btn btn-primary"
relationships_controller
class RelationshipsController < ApplicationController
    def create
      current_user.active_relationships.create(create_params)
    end

    private

    def create_params
      params.permit(:following_id)
    end
end
create.js.erb
$("#follow_form").html(`<div class="btn btn-default">liked</div>`)

When you press the button, the create action will move and the relationship follower will be written in the relationships table.

That's right, it would be nice to get something when matching. I matched, but it was not interesting if it was displayed only as just "like".

So, if you match, I'd like to have a bit of directing. I will introduce this later.


Get matching user list

Match will be established if each other follows each one.

I was able to follow (like) the user by a while ago. I do not know whether it matches that user just by leaving it as it is.

I want to acquire the user who matches the user who is currently logged in, so I will write it for that.

Acquire with the power of ActiveRecord

Get the user you follow and & are your followers. Since we are following each other, we are matching.

Since we want to get the user's followers and compare them with those people are following, add an association.

User.rb
has_many :passive_relationships, class_name: "Relationship", foreign_key: "following_id", dependent: :destroy

Gets the matching user with the user who is logged in.

User.rb
def matchers
  follower_ids = passive_relationships.pluck(:follower_id)
  active_relationships.eager_load(:following)
  .select{|r|follower_ids.include? r.following_id}
  .map{|r|r.following}
end

It's long ...

The user can get it, but I do not want to write this much.

The point is that each other should follow each other's things. A user who has a follower of a user and a follower, and the matching people have matched. I will add a little more association to make this easier to write.

user.rb
has_many :followers, through: :passive_relationships, source: :follower
relationship.rb
belongs_to :follower, class_name: "User"

After adding it is enough to just acquire overlapping users.

def matchers
  following & followers
end

This is OK. However, in either case, the class of the user group taken at this time is Array. If ActiveRecordRelation is good, you can do it in the following way.

###Try hard at Sql and get it

User.matching(current_user)
scope :matching, -> user_id { joins("INNER JOIN relationships ON relationships.follower_id = users.id
  INNER JOIN relationships AS r ON relationships.following_id = r.follower_id AND r.following_id = relationships.follower_id").where('relationships.following_id = ?', user_id) }

If you acquire it like this, class will be ActiveRecord_Relation. I feel like this class is more Happy this time.

###Show matching users In either method, you just call it and you should see the user matching the user.

def index
  @users = current_user.matchers
end
index.html.haml
= render 'partial/navbar'
.container
  .col-md-3
    = render 'partial/verticalnavbar'
  .col-md-9
    .panel.panel-default
      .panel-heading
        .text-center
          %span{style: "font-size:18px;"} ユーザー一覧
      - @users.each do |user|
        .col-sm-4.col-md-3
          .panel.panel-default
            .panel-heading
              %h1.panel-title= link_to "#{user.email}",  user_path(user)
            .panel-body
            .thumbnail
              = image_tag(user.avatar)
            .panel-footer

Try calling view at index.

The current user and the matching users are displayed. For now, the matching function ends.


##Add a production for matching

It was what I was saying to write after a while. After all I want something when matching. It is boring that there is nothing.

Before putting any actions on matching, it is necessary to describe the judgment condition as to whether the user who liked it is following you. Let's make matching by passing the condition.

###Add condition of matching judgment I like to produce a match when I press a button. Writing a description is the moment when an instance of Relationship is created.

relationships_controller.rb
User.find(params["following_id"]).following?(current_user)

If you do it like this, you may be able to decide if the user you like is following you.

###Use criteria Although it seems to be okay to use js.erb as it is now when making a directing, as it is simple, since it is hard to do, because it is hard to do, I normally write Ajax with javascript. Therefore, I will delete the description of remote: true and create.js.erb from the form of the like button that follows the user.

= form_with model: current_user.active_relationships.build, class: 'like_form' do |f|
    %div= hidden_field_tag :following_id, @user.id
    = f.submit "いいね", class: "btn btn-primary"
 $(".like_form").on("submit",function(e){
    e.preventDefault();
    var formData = new FormData(this);
    var url = $(this).attr('action');

    $.ajax({
      url: url,
      type: "POST",
      data: formData,
      dataType: 'json',
      processData: false,
      contentType: false
    })
    .done(function(data){
      //abridgement

I will send it because I want to have the judgment result on the side of js.

following_user = User.find(params["following_id"])
@matching = following_user.following?(current_user)
create.json.jbuilder
# adridgemnt
json.set! :matching, @matching

After that, it is only judged whether js side is true or false. In the case of true, it would be good to include a grand staging.

I made it a Christmas specification. Animation and fireworks whose screen comes from both sides are using mojs.


Additional notes

Adding a chat function is better.

I log in as a different user and send a message to the matching user.

I mainly do two things. · Message input → Send button click → DB save and display with Ajax · Automatically update messages retrieved with Ajax

AUTHOR

READ NEXT

Boostlog is an online community for developers
who want to share ideas and grow each other.

Delete an article

Deleted articles are gone forever. Are you sure?