Skip to content

Instantly share code, notes, and snippets.

@leastbad
Last active September 21, 2020 21:56
Show Gist options
  • Select an option

  • Save leastbad/be335929f98518a033340da0cb9b65da to your computer and use it in GitHub Desktop.

Select an option

Save leastbad/be335929f98518a033340da0cb9b65da to your computer and use it in GitHub Desktop.
Polymorphic comment controller preview

With apologies for the half-baked solution presented, this is the interesting parts of a polymorphic comment engine that makes use of Stimulus, StimulusReflex and CableReady.

Note that app/javascript/controllers/index.js has to set application.consumer = consumer

This was written in the pre-morphs era, so I've done my best to fill in the blanks on what I'd do today in the Reflex.

Not shown: any view templates. Basic idea:

<%= render partial: "comments/comment", collection: @comments %>
class Comment < ApplicationRecord
belongs_to :commentable, polymorphic: true, optional: true
belongs_to :user
after_save do
CommentChannel.broadcast_to(commentable, {})
end
end
class CommentChannel < ApplicationCable::Channel
def subscribed
stream_for params[:commentable_type].constantize.find(params[:commentable_id])
end
end
import { Controller } from 'stimulus'
import StimulusReflex from 'stimulus_reflex'
export default class extends Controller {
static targets = ['comment']
connect () {
this.element['comments'] = this
StimulusReflex.register(this)
if (this.element.dataset.commentableId) {
this.application.consumer.subscriptions.create(
{
channel: 'CommentChannel',
commentable_type: this.element.dataset.commentableType,
commentable_id: this.element.dataset.commentableId
},
{
received (data) {
if (data.cableReady) CableReady.perform(data.operations)
}
}
)
}
}
comment (e) {
e.preventDefault()
if (this.commentTarget.value.length)
this.stimulate('CommentsReflex#comment', {
class: this.element.dataset.commentableType,
id: this.element.dataset.commentableId,
body: this.commentTarget.value
})
this.commentTarget.value = ''
}
}
class CommentsReflex < StimulusReflex::Reflex
def comment(payload)
current_user.comments.create({
body: payload["body"],
commentable_type: payload["class"],
commentable_id: payload["id"],
})
# now that you have updated the comments on this commentable, you could do two things:
# 1. you could do a `render :nothing`, render the partial for the new comment, and then use CableReady.insert_adjacent_html to pop it at the bottom of a list
# 2. you could render the comment partial collection, and then use a selector morph to send the final results into the correct DOM id
# in fact, you can even use the `dom_id` helper because in SR, we prefix the computed id with a `#`
end
end
import { Application } from 'stimulus'
import { definitionsFromContext } from 'stimulus/webpack-helpers'
import StimulusReflex from 'stimulus_reflex'
import consumer from '../channels/consumer'
const application = Application.start()
const context = require.context('controllers', true, /_controller\.js$/)
application.load(definitionsFromContext(context))
application.consumer = consumer
StimulusReflex.initialize(application, { consumer })
if (process.env.RAILS_ENV === 'development') StimulusReflex.debug = true
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment