3

I am building an e-com application and would like to implement something like a messaging system. In the application, all conversation will be related to either a Product model or an Order model. In that case, I would like to store the relating object (type + id, I supposed) to the Conversation object.

To add the fields, of course I can generate and run a migration, however, since the Model and Controller are included within the gem, how can I declare the relationship? (belongs_to :linking_object, :polymorphic) and the controller? Any idea?

Thank you.

Quin
  • 513
  • 5
  • 20

4 Answers4

4

I ended up customizing the Mailboxer gem to allow for a conversationable object to be attached to a conversation.

In models/mailboxer/conversation.rb

belongs_to :conversationable, polymorphic: true

Add the migration to make polymorphic associations work:

add_column :mailboxer_conversations, :conversationable_id, :integer
add_column :mailboxer_conversations, :conversationable_type, :string

In lib/mailboxer/models/messageable.rb you add the conversationable_object to the parameters for send_message:

def send_message(recipients, msg_body, subject, sanitize_text=true, attachment=nil, message_timestamp = Time.now, conversationable_object=nil)
  convo = Mailboxer::ConversationBuilder.new({
    :subject    => subject,
    :conversationable => conversationable_object,
    :created_at => message_timestamp,
    :updated_at => message_timestamp
  }).build

  message = Mailboxer::MessageBuilder.new({
    :sender       => self,
    :conversation => convo,
    :recipients   => recipients,
    :body         => msg_body,
    :subject      => subject,
    :attachment   => attachment,
    :created_at   => message_timestamp,
    :updated_at   => message_timestamp
  }).build

  message.deliver false, sanitize_text
end   

Then you can have conversations around objects:

class Pizza < ActiveRecord::Base
  has_many :conversations, as: :conversationable, class_name: "::Mailboxer::Conversation"    
  ...
end

class Photo < ActiveRecord::Base
  has_many :conversations, as: :conversationable, class_name: "::Mailboxer::Conversation"    
  ...
end

Assuming you have some users set up to message each other

bob = User.find(1)
joe = User.find(2)
pizza = Pizza.create(:name => "Bacon and Garlic")

bob.send_message(joe, "My Favorite", "Let's eat this", true, nil, Time.now, pizza)

Now inside your Message View you can refer to the object:

Pizza Name: <%= @message.conversation.conversationable.name %>
1

Although rewriting a custom Conversation system will be the best long-term solution providing the customization requirement (Like linking with other models for instance), to save some time at the moment I have implement the link with a ConversationLink Model. I hope it would be useful for anyone in the future who are at my position.

Model: conversation_link.rb

class ConversationLink < ActiveRecord::Base
  belongs_to :conversation
  belongs_to :linkingObject, polymorphic: true
end

then in each models I target to link with the conversation, I just add:

has_many :conversation_link, as: :linkingObject

This will only allow you to get the related conversation from the linking object, but the coding for reverse linking can be done via functions defined in a Module.

This is not a perfect solution, but at least I do not need to monkey patch the gem...

Quin
  • 513
  • 5
  • 20
0

The gem automatically take care of this for you, as they have built a solution that any model in your own domain logic can act as a messagble object.

Simply declaring

acts_as_messagable

In your Order or Product model will accomplish what you are looking for.

TheIrishGuy
  • 2,531
  • 19
  • 23
  • Hi @TheIrishGuy, thanks for your reply. However, the `acts_as_messageable` only allow the gem to know which object can be `sender` and `receiver` of the gem. What the app need is attaching a `product` or `order` to the conversation but the sender and receiver are still Users – Quin Apr 07 '14 at 14:18
  • 1
    Ok, what you'll want to do than is create a concern with your custom logic. Than monkey patch the conversations class to include that concern. – TheIrishGuy Apr 07 '14 at 17:38
0

You could just use something like:

form_helper :products

and add those fields to the message form

but mailboxer comes with attachment functionality(carrierwave) included

this might help if you need something like attachments in your messages:

https://stackoverflow.com/a/12199364/1230075

Community
  • 1
  • 1
franklinexpress
  • 1,149
  • 14
  • 44
  • Hi @Franklin-De-Los-Santos, thanks for your reply. What I need is to relate a conversation with an model object so that's slightly different. I am thinking if there are no more straight forward options than monkey patching the gem, I would prefer to add another model which is completely separated with the gem instead... – Quin Apr 08 '14 at 09:52