Skip to content

Instantly share code, notes, and snippets.

@mh-mobile
Last active April 21, 2020 10:48
Show Gist options
  • Save mh-mobile/2fcf17570bef032872ceb4f48be756a5 to your computer and use it in GitHub Desktop.
Save mh-mobile/2fcf17570bef032872ceb4f48be756a5 to your computer and use it in GitHub Desktop.
follow relationship
# frozen_string_literal: true
require "bundler/inline"
gemfile(true) do
source "https://rubygems.org"
git_source(:github) { |repo| "https://github.com/#{repo}.git" }
# Activate the gem you are reporting the issue against.
gem "activerecord", "6.0.0"
gem "sqlite3"
gem "byebug"
end
require "active_record"
require "minitest/autorun"
require "logger"
# This connection will do for database-independent bug reports.
ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:")
ActiveRecord::Base.logger = Logger.new(STDOUT)
ActiveRecord::Schema.define do
create_table :users, force: true do |t|
t.string :name, null: false
end
create_table :friendships, force: true do |t|
t.belongs_to :follower
t.belongs_to :followed
end
add_index :friendships, [:follower_id, :followed_id], unique: true
create_table :books, force: true do |t|
t.string :user_id
t.string :name
end
end
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
end
class User < ApplicationRecord
has_many :books
has_many :friendships, foreign_key: "follower_id", dependent: :destroy
has_many :reverse_friendships, foreign_key: "followed_id", class_name: "Friendship", dependent: :destroy
has_many :following, through: :friendships, source: :followed, class_name: "User"
has_many :followers, through: :reverse_friendships, class_name: "User"
has_many :following_books, through: :following, source: :books, class_name: "Book"
def follow!(user)
# friendships.create!(followed_id: user.id)
following << user
end
def unfollow!(user)
friendships.find_by!(followed_id: user.id).destroy!
end
def following?(user)
following.include?(user)
end
end
class Friendship < ApplicationRecord
belongs_to :follower, class_name: "User"
belongs_to :followed, class_name: "User"
end
class Book < ApplicationRecord
belongs_to :user
default_scope -> { order('create_at DESC') }
def self.friend_feeds(user)
# 自分の持つ書籍とフォローユーザーが持つ書籍を取得する
following_ids = "select followed_id from friendships where follower_id = :user_id"
where("user_id in (#{following_ids}) or user_id = :user_id", user_id: user.id)
end
end
class FriendshipTest < Minitest::Test
def test_association
# テストデータ作成
mh = User.create!(name: "mh")
ruby_book = Book.create!(name: "ruby", user_id: mh.id)
js_book = Book.create!(name: "js", user_id: mh.id)
miro = User.create!(name: "miro")
php_book = Book.create!(name: "php", user_id: miro.id)
python_book = Book.create!(name: "python", user_id: miro.id)
swift_book = Book.create!(name: "swift", user_id: miro.id)
haru = User.create!(name: "haru")
rust_book = Book.create!(name: "rust", user_id: haru.id)
typescript_book = Book.create!(name: "typescript", user_id: haru.id)
go_book = Book.create!(name: "go", user_id: haru.id)
kotlin = Book.create!(name: "kotlin", user_id: haru.id)
# フォローの関連付け
assert_equal false, mh.following?(miro)
assert_equal false, mh.following?(haru)
mh.follow!(miro)
mh.follow!(haru)
assert_equal true, mh.following?(miro)
assert_equal true, mh.following?(haru)
# フォローユーザーの取得
following = mh.following
# フォローが正しい
assert_equal 2, following.count
assert_equal miro, following[0]
assert_equal haru, following[1]
# フォローユーザーの書籍の数が正しい
following_books = mh.following_books
assert_equal 7, following_books.count
# 自分を含めたフォローユーザーの書籍のフィードを取得
feeds = Book.friend_feeds(mh)
assert_equal 9, feeds.count
# フォローを解除
mh.unfollow!(miro)
mh.reload
following = mh.following
# フォローが正しい
assert_equal 1, following.count
assert_equal haru, following[0]
assert_equal false, mh.following?(miro)
assert_equal true, mh.following?(haru)
# mhユーザーを削除
mh.destroy
# Friendshipのデータ数が0になる
assert_equal 0, Friendship.all.count
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment