-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Feature/add rich text reaction model (#451)
* feat: add RichTextReaction model * feat: rollback and remigrate RichTextReaction creation with emoji and user_id columns * chore: add missing association * feat: allow RichTextReaction to interface with a limited set of emojis and captions * feat: add routes and actions for rich text reaction create and destroy * refactor: Emoji class isn't needed * feat: add rich text reaction view component * feat: have standup update rendered with emoji selector * chore: comment for future improvement * refacto: improve test * refactor: organize in order to more easily add new rich text reaction components * rubocop corrections - Removed test from meeting_update_component_spec.rb to add in a new branch. * refactor: using the emoji text as the key is easier to use with better code readability * chore: remove temporary components that were used for testing * feat: gather reaction info for all rich text of a class * chore: EmojiSelectorComponent has been deleted * refactor: use a more fitting column name * clean up * rubocop corrections * refactor: store emojis and their captions for global usage * refactor: `Reactionable` is not a fitting way of DRYing up as of now * chore: use `require` for the one lib class * refactor: emojis and their captions defnitions were moved * refactor: change Emoji to a reusable class that provides API for frontend code * fix: rescuing the error doesn't stop ctlr action flow - Moved rescue into #destroy since it's the only action that requires the logic. * chore: clean up tests * chore: rubocop corrections * chore: add helpful comment * feat: update Emoji for easier API for frontend to use * feat: scope for finding all reactions belonging to given rich text(s) * rubocop * refactor: eliminate view component query and do some clean up * clean up * chore: revert changes that should go in another branch * chore: remove scopes that are too trivial and aren't even needed yet * feat: add factory for ActionText::RichText, skip lint * chore: add test for code coverage
- Loading branch information
Showing
16 changed files
with
296 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
class RichTextReactionsController < ApplicationController | ||
before_action :build_rich_text_reaction, only: %i[create] | ||
|
||
# POST /rich_text_reactions.turbo_stream | ||
def create | ||
if @rich_text_reaction.save | ||
render :create, status: :created | ||
else | ||
flash.now[:alert] = 'Reaction could not be created.' | ||
end | ||
end | ||
|
||
# DELETE /rich_text_reactions/:id.turbo_stream | ||
def destroy | ||
@rich_text_reaction = RichTextReaction.find(params[:id]) | ||
|
||
msg = 'Reaction could not be deleted.' | ||
flash.now[:alert] = msg unless @rich_text_reaction.destroy | ||
rescue ActiveRecord::RecordNotFound | ||
flash.now[:alert] = "RichTextReaction with id #{params[:id]} could not be found." | ||
end | ||
|
||
private | ||
|
||
def build_rich_text_reaction | ||
@rich_text_reaction = current_user.rich_text_reactions.build( | ||
rich_text_reaction_params | ||
) | ||
end | ||
|
||
def rich_text_reaction_params | ||
params.require(:rich_text_reaction).permit(:emoji_caption, :rich_text_id) | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
# == Schema Information | ||
# | ||
# Table name: rich_text_reactions | ||
# | ||
# id :bigint not null, primary key | ||
# emoji_caption :string not null | ||
# created_at :datetime not null | ||
# updated_at :datetime not null | ||
# rich_text_id :bigint not null | ||
# user_id :bigint not null | ||
# | ||
# Indexes | ||
# | ||
# index_rich_text_reactions_on_rich_text_id (rich_text_id) | ||
# index_rich_text_reactions_on_user_id (user_id) | ||
# | ||
# Foreign Keys | ||
# | ||
# fk_rails_... (rich_text_id => action_text_rich_texts.id) | ||
# fk_rails_... (user_id => users.id) | ||
# | ||
require 'emoji' | ||
|
||
class RichTextReaction < ApplicationRecord | ||
belongs_to :user | ||
belongs_to :rich_text, class_name: 'ActionText::RichText' | ||
|
||
validates :emoji_caption, | ||
inclusion: { | ||
in: Emoji.captions, | ||
message: 'must be present in permissible set' | ||
} | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
<%= "PLACEHOLDER" %> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -69,4 +69,6 @@ | |
scope controller: :static do | ||
get :faq | ||
end | ||
|
||
resources :rich_text_reactions, only: %i[create destroy] | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
class CreateRichTextReactions < ActiveRecord::Migration[7.0] | ||
def change | ||
create_table :rich_text_reactions do |t| | ||
t.references :user, null: false, foreign_key: true | ||
t.references :rich_text, null: false, foreign_key: { to_table: :action_text_rich_texts } | ||
t.string :emoji_caption, null: false | ||
|
||
t.timestamps | ||
end | ||
end | ||
end |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
# frozen_string_literal: true | ||
|
||
class Emoji | ||
DICTIONARY = { | ||
'THUMBS_UP' => '👍', | ||
'THUMBS_DOWN' => '👎', | ||
'THINKING' => '🤔', | ||
'HOORAY' => '🎉', | ||
'SHRUG' => '🤷', | ||
'EYES' => '👀' | ||
}.freeze | ||
|
||
attr_reader :caption | ||
|
||
def initialize(caption = DICTIONARY.keys.sample) | ||
@caption = caption | ||
end | ||
|
||
def emoji | ||
DICTIONARY[@caption] | ||
end | ||
|
||
class << self | ||
def captions | ||
DICTIONARY.keys | ||
end | ||
|
||
def emojis | ||
DICTIONARY.values | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
FactoryBot.define do | ||
factory :action_text_rich_text, class: 'ActionText::RichText' do | ||
# +rich_text_owner+ must be given by the user of this factory, and it may | ||
# be any persisted ActiveRecord model record. | ||
transient do | ||
rich_text_owner { nil } | ||
end | ||
|
||
name { Faker::Lorem.word } | ||
body { ActionText::Content.new "<div>#{Faker::Lorem.sentence}</div>" } | ||
|
||
after(:build) do |action_text_rich_text, evaluator| | ||
if evaluator.rich_text_owner | ||
action_text_rich_text.record_type = evaluator.rich_text_owner.class.name | ||
action_text_rich_text.record_id = evaluator.rich_text_owner.id | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
# == Schema Information | ||
# | ||
# Table name: rich_text_reactions | ||
# | ||
# id :bigint not null, primary key | ||
# emoji_caption :string not null | ||
# created_at :datetime not null | ||
# updated_at :datetime not null | ||
# rich_text_id :bigint not null | ||
# user_id :bigint not null | ||
# | ||
# Indexes | ||
# | ||
# index_rich_text_reactions_on_rich_text_id (rich_text_id) | ||
# index_rich_text_reactions_on_user_id (user_id) | ||
# | ||
# Foreign Keys | ||
# | ||
# fk_rails_... (rich_text_id => action_text_rich_texts.id) | ||
# fk_rails_... (user_id => users.id) | ||
# | ||
FactoryBot.define do | ||
factory :rich_text_reaction do | ||
# +rich_text_owner+ can be given by the user of this factory, and it may | ||
# be any persisted ActiveRecord model record. By default, a User record is | ||
# used. | ||
transient do | ||
rich_text_owner { user } | ||
end | ||
|
||
user | ||
emoji_caption { Emoji.captions.sample } | ||
rich_text { association(:action_text_rich_text, rich_text_owner:) } | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
require 'rails_helper' | ||
require 'emoji' | ||
|
||
RSpec.describe Emoji do | ||
let(:caption) { described_class.captions.sample } | ||
|
||
describe '#emoji' do | ||
subject { described_class.new(caption) } | ||
|
||
it 'returns the emoji in string format' do | ||
expect(subject.emoji).to eq(Emoji::DICTIONARY[caption]) | ||
end | ||
end | ||
|
||
describe '.captions' do | ||
it 'returns the set of allowed emoji captions' do | ||
expect(described_class.captions).to eq(described_class::DICTIONARY.keys) | ||
end | ||
end | ||
|
||
describe '.emojis' do | ||
it 'returns the set of allowed emojis' do | ||
expect(described_class.emojis).to eq(described_class::DICTIONARY.values) | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
require 'rails_helper' | ||
|
||
RSpec.describe RichTextReaction do | ||
it 'is valid with an emoji in the permissible set' do | ||
emoji_caption = Emoji.captions.sample | ||
rich_text_reaction = described_class.new(emoji_caption:) | ||
|
||
expect(rich_text_reaction.errors[:emoji_caption]).to be_empty | ||
end | ||
|
||
it 'is invalid with an emoji not in the permissible set' do | ||
rich_text_reaction = described_class.new(emoji_caption: 'disguised_face') | ||
rich_text_reaction.valid? | ||
|
||
expect(rich_text_reaction.errors[:emoji_caption]).to be_present | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
require 'rails_helper' | ||
require 'emoji' | ||
|
||
RSpec.describe 'RichTextReaction requests' do | ||
let!(:user) { create(:user) } | ||
|
||
before do | ||
sign_in user | ||
end | ||
|
||
describe 'POST /rich_text_reactions' do | ||
it 'creates a rich text reaction' do | ||
count = RichTextReaction.count | ||
params = { | ||
rich_text_reaction: { | ||
emoji_caption: Emoji.captions.sample, | ||
rich_text_id: create(:standup_meeting).yesterday_work_description.id | ||
}, | ||
format: :turbo_stream | ||
} | ||
|
||
post(rich_text_reactions_url, params:) | ||
|
||
expect(RichTextReaction.count).to eq(count + 1) | ||
expect(response).to have_http_status :created | ||
end | ||
|
||
it 'sets a flash message to indicate failure to create' do | ||
post rich_text_reactions_url, | ||
params: { | ||
rich_text_reaction: { | ||
emoji_caption: Emoji.captions.sample, | ||
rich_text_id: 2 | ||
}, | ||
format: :turbo_stream | ||
} | ||
|
||
expect(flash.now[:alert]).to be_present | ||
end | ||
end | ||
|
||
describe 'DELETE /rich_text_reactions/:id' do | ||
it 'deletes a rich text reaction' do | ||
id = create(:rich_text_reaction).id | ||
|
||
delete(rich_text_reaction_url(id), params: { format: :turbo_stream }) | ||
|
||
expect(RichTextReaction.count).to be_zero | ||
expect(response).to have_http_status :no_content | ||
end | ||
|
||
it 'sets a flash message to indicate failure to delete' do | ||
fake_id = '1' | ||
rich_text_reaction = instance_double(RichTextReaction, destroy: false) | ||
allow(RichTextReaction).to receive(:find).with(fake_id).and_return(rich_text_reaction) | ||
|
||
delete rich_text_reaction_url(fake_id), | ||
params: { | ||
format: :turbo_stream | ||
} | ||
|
||
expect(flash.now[:alert]).to be_present | ||
|
||
expect(response).to have_http_status :no_content | ||
end | ||
end | ||
end |