mirror of
https://github.com/Growstuff/growstuff.git
synced 2026-01-01 22:17:49 -05:00
This change introduces polymorphic comments, allowing you to comment on Photos, Plantings, Harvests, and Activities, in addition to Posts.
Key changes include:
- **Comment Model:**
- Made `Comment.commentable` a polymorphic association.
- Added a data migration to move existing post comments to the new structure.
- Updated notification creation logic for polymorphic commentables.
- **CommentsController:**
- Refactored to handle various commentable types using a `find_commentable` method.
- **Ability Model:**
- Updated permissions for comment creation, editing (author/admin), and deletion (author/commentable owner/admin).
- **Routes:**
- Added nested comment routes for Photos, Plantings, Harvests, Activities, and Posts using a `commentable` concern with shallow routes.
- **Views:**
- Created generic partials for comment forms (`_form.html.haml`) and display (`_comment.html.haml`, `_comments.html.haml`).
- Integrated these partials into the show pages of all commentable types.
- Updated `comments/new` and `comments/edit` views to be generic.
- Relevant parent controller `show` actions now eager-load comments.
- **Testing:**
- Added extensive model, controller (using shared examples), and feature tests to cover the new polymorphic comment functionality, including permissions and UI interactions for all commentable types.
- Updated and created factories as needed.
This fulfills the issue requirements for adding comments to multiple resource types with appropriate permissions.
156 lines
5.7 KiB
Ruby
156 lines
5.7 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require 'rails_helper'
|
|
|
|
describe Comment do
|
|
context "associations" do
|
|
let(:member) { FactoryBot.create(:member) } # Common author
|
|
|
|
it "belongs to a commentable (Post)" do
|
|
post = FactoryBot.create(:post, author: member)
|
|
comment = FactoryBot.create(:comment, commentable: post, author: member)
|
|
comment.commentable.should be_an_instance_of Post
|
|
end
|
|
|
|
it "belongs to a commentable (Photo)" do
|
|
photo = FactoryBot.create(:photo, owner: member)
|
|
comment = FactoryBot.create(:comment, commentable: photo, author: member)
|
|
comment.commentable.should be_an_instance_of Photo
|
|
end
|
|
|
|
it "belongs to a commentable (Planting)" do
|
|
planting = FactoryBot.create(:planting, owner: member)
|
|
comment = FactoryBot.create(:comment, commentable: planting, author: member)
|
|
comment.commentable.should be_an_instance_of Planting
|
|
end
|
|
|
|
it "belongs to a commentable (Harvest)" do
|
|
harvest = FactoryBot.create(:harvest, owner: member)
|
|
comment = FactoryBot.create(:comment, commentable: harvest, author: member)
|
|
comment.commentable.should be_an_instance_of Harvest
|
|
end
|
|
|
|
it "belongs to a commentable (Activity)" do
|
|
activity = FactoryBot.create(:activity, owner: member)
|
|
comment = FactoryBot.create(:comment, commentable: activity, author: member)
|
|
comment.commentable.should be_an_instance_of Activity
|
|
end
|
|
|
|
it "belongs to an author" do
|
|
comment = FactoryBot.create(:comment, author: member) # Default commentable is Post
|
|
comment.author.should be_an_instance_of Member
|
|
end
|
|
end
|
|
|
|
RSpec.shared_examples "comment notifications" do |commentable_type, commentable_factory_name|
|
|
let(:commentable_owner) { FactoryBot.create(:member) }
|
|
let(:comment_author) { FactoryBot.create(:member) }
|
|
let!(:commentable) do
|
|
# For :post, the owner is :author. For others, it's :owner.
|
|
if commentable_factory_name == :post
|
|
FactoryBot.create(commentable_factory_name, author: commentable_owner)
|
|
else
|
|
FactoryBot.create(commentable_factory_name, owner: commentable_owner)
|
|
end
|
|
end
|
|
|
|
it "sends a notification when a comment is posted" do
|
|
expect do
|
|
FactoryBot.create(:comment, commentable: commentable, author: comment_author)
|
|
end.to change(Notification, :count).by(1)
|
|
end
|
|
|
|
it "sets the notification fields correctly" do
|
|
comment = FactoryBot.create(:comment, commentable: commentable, author: comment_author)
|
|
notification = Notification.last # More robust than Notification.first
|
|
notification.sender.should eq comment.author
|
|
notification.recipient.should eq commentable_owner
|
|
notification.subject.should include "commented on your #{commentable_type.downcase}"
|
|
notification.body.should eq comment.body
|
|
notification.commentable_id.should eq commentable.id
|
|
notification.commentable_type.should eq commentable_type
|
|
end
|
|
|
|
it "doesn't send notifications to yourself (when comment author is commentable owner)" do
|
|
expect do
|
|
FactoryBot.create(:comment, commentable: commentable, author: commentable_owner)
|
|
end.not_to change(Notification, :count)
|
|
end
|
|
end
|
|
|
|
context "notifications for Post" do
|
|
include_examples "comment notifications", "Post", :post
|
|
end
|
|
|
|
context "notifications for Photo" do
|
|
include_examples "comment notifications", "Photo", :photo
|
|
end
|
|
|
|
context "notifications for Planting" do
|
|
include_examples "comment notifications", "Planting", :planting
|
|
end
|
|
|
|
context "notifications for Harvest" do
|
|
include_examples "comment notifications", "Harvest", :harvest
|
|
end
|
|
|
|
context "notifications for Activity" do
|
|
include_examples "comment notifications", "Activity", :activity
|
|
end
|
|
|
|
RSpec.shared_examples "comment to_s method" do |commentable_type, commentable_factory_name|
|
|
let(:commentable_owner) { FactoryBot.create(:member) }
|
|
let(:comment_author) { FactoryBot.create(:member, login_name: "CommenterUser") }
|
|
let!(:commentable) do
|
|
# For :post, the owner is :author. For others, it's :owner.
|
|
obj = if commentable_factory_name == :post
|
|
FactoryBot.create(commentable_factory_name, author: commentable_owner)
|
|
else
|
|
FactoryBot.create(commentable_factory_name, owner: commentable_owner)
|
|
end
|
|
# Ensure commentable has a consistent ID for the test if possible, or just use its class name
|
|
obj
|
|
end
|
|
let(:comment) { FactoryBot.create(:comment, commentable: commentable, author: comment_author) }
|
|
|
|
it "returns a descriptive string" do
|
|
expected_string = "#{comment_author.login_name} commented on #{commentable_type.downcase} ##{commentable.id}"
|
|
comment.to_s.should eq expected_string
|
|
end
|
|
end
|
|
|
|
context "to_s method for Post" do
|
|
include_examples "comment to_s method", "Post", :post
|
|
end
|
|
|
|
context "to_s method for Photo" do
|
|
include_examples "comment to_s method", "Photo", :photo
|
|
end
|
|
|
|
context "to_s method for Planting" do
|
|
include_examples "comment to_s method", "Planting", :planting
|
|
end
|
|
|
|
context "to_s method for Harvest" do
|
|
include_examples "comment to_s method", "Harvest", :harvest
|
|
end
|
|
|
|
context "to_s method for Activity" do
|
|
include_examples "comment to_s method", "Activity", :activity
|
|
end
|
|
|
|
context "ordering" do
|
|
before do
|
|
@m = FactoryBot.create(:member)
|
|
# Ensure the commentable for ordering test is a Post, as it was originally
|
|
@p = FactoryBot.create(:post, author: @m)
|
|
@c1 = FactoryBot.create(:comment, commentable: @p, author: @m)
|
|
@c2 = FactoryBot.create(:comment, commentable: @p, author: @m)
|
|
end
|
|
|
|
it 'has a scope for ASC order for displaying on commentable page' do # Renamed for clarity
|
|
described_class.post_order.should eq [@c1, @c2]
|
|
end
|
|
end
|
|
end
|