mercredi 9 septembre 2015

Check if a conversation between two or more specific users already exists, where users-conversations have a HABTM association

A user has and belongs to many conversations. A conversation has and belongs to many users and has many messages. A message belongs to a user and belongs to a conversation.

A very simple relationship model, initially working perfectly, but now giving me a headache as I refactor it to work for group messages, i.e. messages between more than two users.

I've only worked shallowly with HABTM associations before and can't figure out how to check if a conversation already exists between a given array of users. This check will happen in the conversations_controller, probably via a scope defined in the model.

models/conversation.rb

class Conversation < ActiveRecord::Base
  has_and_belongs_to_many :users
  has_many :messages, dependent: :destroy

  scope :between, -> users do
    uhhhhhhhhh???
    something like
    users.each do |u|
      then a where("conversations.user.id = ?").yadayadayada query
    end
  end
end

controllers/conversations_controller.rb

[snip]

def create
  if Conversation.between(params[:users]).present?
    @conversation = Conversation.between(params[:users]).first
  else
    @conversation = Conversation.create!(conversation_params)
  end
    redirect_to conversation_messages_path(@conversation)
end

models/user.rb

class User < ActiveRecord::Base
  has_and_belongs_to_many :conversations
  [snip lots of other stuff]
end

models/message.rb

class Message < ActiveRecord::Base
  belongs_to :conversation
  belongs_to :user
  validates_presence_of :body, :conversation_id, :user_id
end

db/migrate/create_messages.rb

class CreateMessages < ActiveRecord::Migration
  def up
    create_table :messages do |t|
      t.text :body
      t.references :conversation, index: true
      t.references :user, index: true
      t.boolean :read, :default => false

      t.timestamps
    end
  end

  def down
    drop_table :messages
  end
end

db/migrate/create_conversations.rb

class CreateConversations < ActiveRecord::Migration
  def change
    create_table :conversations do |t|
      t.string :subject
      t.timestamps
    end
    end

  def down
    drop_table :conversations
  end
end

db/migrate/create_conversations_users_join

class CreateConversationsUsersJoin < ActiveRecord::Migration
  def change
    create_table :conversations_users, id: false do |t|
        t.belongs_to :conversation, index: true
        t.belongs_to :user, index: true
    end
  end
end

Aucun commentaire:

Enregistrer un commentaire