From b4d0afe90d065c10913ee4451fb342c7329bee34 Mon Sep 17 00:00:00 2001 From: "Jesse C. Fisher" Date: Tue, 21 Nov 2023 17:19:33 +0000 Subject: [PATCH] Use polymorphic relationships for followable --- app/controllers/profiles_controller.rb | 1 + app/controllers/projects_controller.rb | 1 + app/controllers/relationships_controller.rb | 15 ++++++++------- app/models/profile.rb | 8 ++++++-- app/models/project.rb | 8 ++++---- app/models/relationship.rb | 6 ++++-- app/models/user.rb | 16 +++++++++++----- app/views/projects/show.html.haml | 5 ++++- app/views/shared/_follow.html.haml | 3 ++- app/views/shared/_follow_form.html.haml | 4 ++-- .../{profiles => shared}/_unfollow.html.haml | 2 +- ...31121150256_add_followable_to_relationship.rb | 5 +++++ db/schema.rb | 5 ++++- 13 files changed, 53 insertions(+), 26 deletions(-) rename app/views/{profiles => shared}/_unfollow.html.haml (54%) create mode 100644 db/migrate/20231121150256_add_followable_to_relationship.rb diff --git a/app/controllers/profiles_controller.rb b/app/controllers/profiles_controller.rb index b83fe368..876480b0 100644 --- a/app/controllers/profiles_controller.rb +++ b/app/controllers/profiles_controller.rb @@ -10,6 +10,7 @@ class ProfilesController < ApplicationController # GET /profiles/1 or /profiles/1.json def show authorize @profile + @followable = @profile if @profile.user == current_user @micropost = @profile.microposts.build else diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 4df69123..c410d575 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -9,6 +9,7 @@ class ProjectsController < ApplicationController # GET /projects/1 or /projects/1.json def show authorize @project + @followable = @project end # GET /projects/new diff --git a/app/controllers/relationships_controller.rb b/app/controllers/relationships_controller.rb index e328cc73..c5288dce 100644 --- a/app/controllers/relationships_controller.rb +++ b/app/controllers/relationships_controller.rb @@ -1,15 +1,16 @@ class RelationshipsController < ApplicationController def create - profile = Profile.find(params[:followed_id]) authorize Relationship - current_user.follow(profile) - redirect_to profile + leader = params[:followable_type].constantize.find(params[:followable_id]) + current_user.follow(leader) + redirect_to leader end def destroy - profile = Relationship.find(params[:id]).followed - authorize profile - current_user.unfollow(profile) - redirect_to profile + relationship = Relationship.find(params[:id]) + authorize relationship + leader = relationship.followable + current_user.unfollow(leader) + redirect_to leader end end diff --git a/app/models/profile.rb b/app/models/profile.rb index 14225d5b..91a51475 100644 --- a/app/models/profile.rb +++ b/app/models/profile.rb @@ -2,11 +2,15 @@ class Profile < ActiveRecord::Base belongs_to :user has_many :social_links has_many :passive_relationships, class_name: "Relationship", - foreign_key: "followed_id", + foreign_key: "followable_id", dependent: :destroy - has_many :followers, through: :passive_relationships, source: :follower + # has_many :followers, through: :passive_relationships, source: :follower has_many :microposts, as: :micropostable + def followers + Relationship.where("followable_id = ? AND followable_type = ?", self.id, self.class.to_s) + end + def display_name name end diff --git a/app/models/project.rb b/app/models/project.rb index 6d9d4040..44ffa69e 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -1,10 +1,10 @@ class Project < ActiveRecord::Base belongs_to :user has_many :microposts, as: :micropostable - has_many :passive_relationships, class_name: "Relationship", - foreign_key: "followed_id", - dependent: :destroy - has_many :followers, through: :passive_relationships, source: :follower + + def followers + Relationship.where("followable_id = ? AND followable_type = ?", self.id, self.class.to_s) + end def display_name title diff --git a/app/models/relationship.rb b/app/models/relationship.rb index 4f159a84..5472ecd1 100644 --- a/app/models/relationship.rb +++ b/app/models/relationship.rb @@ -1,6 +1,8 @@ class Relationship < ActiveRecord::Base belongs_to :follower, class_name: "User" - belongs_to :followed, class_name: "Profile" validates :follower_id, presence: true - validates :followed_id, presence: true + belongs_to :followable, polymorphic: true + # belongs_to :followed, class_name: "Profile" + # validates :followed_id, presence: true + # belongs_to :followerable, polymorphic: true end diff --git a/app/models/user.rb b/app/models/user.rb index 9bc85b7c..b6997839 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -10,7 +10,9 @@ class User < ActiveRecord::Base has_many :active_relationships, class_name: "Relationship", foreign_key: "follower_id", dependent: :destroy - has_many :following, through: :active_relationships, source: :followed + # has_many :following, through: :active_relationships, source: :followed + has_many :following_profiles, through: :active_relationships, source: :followable, source_type: "Profile" + has_many :following_projects, through: :active_relationships, source: :followable, source_type: "Project" has_many :microposts, as: :micropostable def icid @@ -106,14 +108,18 @@ class User < ActiveRecord::Base devise :invitable, :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable - # Follows a user. + # Follows a followable leader def follow(leader) - active_relationships.create(followed_id: leader.id) + active_relationships.create(followable_id: leader.id, followable_type: leader.class.to_s) end - # Unfollows a user. + # Unfollows a followable leader def unfollow(leader) - active_relationships.find_by(followed_id: leader.id).destroy + active_relationships.find_by(followable_id: leader.id, followable_type: leader.class.to_s).destroy + end + + def following + active_relationships.map{|ar| ar.followable } end # Returns true if the current user is following the leader. diff --git a/app/views/projects/show.html.haml b/app/views/projects/show.html.haml index 32c014d2..94f388b9 100644 --- a/app/views/projects/show.html.haml +++ b/app/views/projects/show.html.haml @@ -3,11 +3,14 @@ = @project.title - if policy(@project).edit? = link_to 'Edit', edit_project_path(@project) - -# = render 'shared/follow_form' if current_user.signed_in? + = render 'shared/follow_form' if current_user.signed_in? .description = @project.description +.stats + %p #{@project.followers.count} Followers + - if @project.microposts.any? %section.microposts %h3 Posts #{@project.microposts.count} diff --git a/app/views/shared/_follow.html.haml b/app/views/shared/_follow.html.haml index 69335a2c..db7b74b4 100644 --- a/app/views/shared/_follow.html.haml +++ b/app/views/shared/_follow.html.haml @@ -1,3 +1,4 @@ = form_for(current_user.active_relationships.build) do |f| - %div= hidden_field_tag :followed_id, @profile.id + %div= hidden_field_tag :followable_id, @followable.id + %div= hidden_field_tag :followable_type, @followable.class.to_s = f.submit "Follow" diff --git a/app/views/shared/_follow_form.html.haml b/app/views/shared/_follow_form.html.haml index 942af0cd..d1d66f02 100644 --- a/app/views/shared/_follow_form.html.haml +++ b/app/views/shared/_follow_form.html.haml @@ -1,5 +1,5 @@ #follow_form - - if current_user.following?(@profile) - = render 'unfollow' + - if current_user.following?(@followable) + = render 'shared/unfollow' - else = render 'shared/follow' diff --git a/app/views/profiles/_unfollow.html.haml b/app/views/shared/_unfollow.html.haml similarity index 54% rename from app/views/profiles/_unfollow.html.haml rename to app/views/shared/_unfollow.html.haml index 3a5fcf67..140fd846 100644 --- a/app/views/profiles/_unfollow.html.haml +++ b/app/views/shared/_unfollow.html.haml @@ -1,3 +1,3 @@ -= form_for(current_user.active_relationships.find_by(followed_id: @profile.id), | += form_for(current_user.active_relationships.find_by(followable_id: @followable.id), | html: { method: :delete }) do |f| | = f.submit "Unfollow" diff --git a/db/migrate/20231121150256_add_followable_to_relationship.rb b/db/migrate/20231121150256_add_followable_to_relationship.rb new file mode 100644 index 00000000..34d5f5b5 --- /dev/null +++ b/db/migrate/20231121150256_add_followable_to_relationship.rb @@ -0,0 +1,5 @@ +class AddFollowableToRelationship < ActiveRecord::Migration[6.1] + def change + add_reference :relationships, :followable, polymorphic: true + end +end diff --git a/db/schema.rb b/db/schema.rb index 814443f2..3e259abb 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2023_11_14_160910) do +ActiveRecord::Schema.define(version: 2023_11_21_150256) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -129,6 +129,9 @@ ActiveRecord::Schema.define(version: 2023_11_14_160910) do t.integer "followed_id" t.datetime "created_at", precision: 6, null: false t.datetime "updated_at", precision: 6, null: false + t.string "followable_type" + t.bigint "followable_id" + t.index ["followable_type", "followable_id"], name: "index_relationships_on_followable" t.index ["followed_id"], name: "index_relationships_on_followed_id" t.index ["follower_id", "followed_id"], name: "index_relationships_on_follower_id_and_followed_id", unique: true t.index ["follower_id"], name: "index_relationships_on_follower_id"