I'm new to Rails and i've been trying out Active Job and Action Cable and also Presenter and I've searched all over the place but not being able to figure it out.
so my question is that is there any way to use presenter in a partial and render it outside a controller(in ActiveJob for example)?
below is what i am wanting to achieve:
I have a message system(more like an email), with conversations controller and messages controller. What I want to achieve is when somebody starts a new conversation, if the receiver is on the conversation index page, the new conversation automatically appends to their index view.(like in emails) by using ActionCable
So, my conversation.rb
class Conversation < ApplicationRecord
has_many :messages, dependent: :destroy
after_create_commit { ConversationBroadcastJob.perform_later(self) }
conversation_broadcast_job.rb
class ConversationBroadcastJob < ApplicationJob
queue_as :default
def perform(conversation)
ActionCable.server.broadcast "conversations:#{conversation.receiver_id}",
{convo: render_conversation(conversation)}
end
private
def render_conversation(conversation)
ConversationsController.render(partial: 'conversations/conversation',
locals: {conversation: conversation, var: 'not'})
end
end
and my _conversation.html.erb, I used a Presenter by following this episode of RailCast
<% present conversation do |conversation_presenter| %>
<div class="conversation <%=conversation_presenter.css(var)%>"
id="conversation_<%= conversation.id %>"
data-sender-id='<%= conversation_presenter.sender_id%>'>
<%=conversation_presenter.avatar%>
<div class="conversation-counterpart-name conversation-info truncate">
<%=conversation_presenter.name(var) %>
</div>
<div class='conversation-subject conversation-info truncate'>
<%=link_to conversation_messages_path(conversation),
class:'link-gray truncate' do |n|%>
<%=conversation_presenter.subject %>
<div class='last-message truncate'>
<%=conversation_presenter.last_message%>
</div>
<% end %>
</div>
<div class="conversation-date conversation-info">
<%=conversation_presenter.last_date%>
</div>
</div>
<% end %>
The present method is defined in ApplicationHelper
def present(object, klass = nil)
klass ||= "#{object.class}Presenter".constantize
presenter = klass.new(object, self)
yield presenter if block_given?
presenter
end
conversation_presenter.rb
class ConversationPresenter < BasePresenter
presents :conversation
delegate :subject, to: :conversation
def name(var)
if conversation.sender_id == var.id
conversation.receiver.name
else
conversation.sender.name
end
end
def last_date
if conversation.last_msg.nil?
conversation.render_date
else
conversation.last_msg.render_date
end
end
def last_message
conversation.last_msg.content unless conversation.last_msg.nil?
end
def avatar
h.image_tag('avatar.svg', size: 30, class:'conversation- counterpart-avatar')
end
def css(var)
"unread" unless
conversation.read || (!conversation.last_msg.nil? && conversation.last_msg.wrote_by(var))
end
def sender_id
if conversation.last_msg.nil?
conversation.sender_id
else
conversation.last_msg.author_id
end
end
end
The problem starts from here, the partial won't get rendered in the ActiveJob, because of the conversation presenter I assume. So my question is that is there anyway to use presenter with rendering outside a controller?
Please let me know if you need any information about other part of my codes
Thanks!