How to set two users to chat together

坚强是说给别人听的谎言 提交于 2019-12-12 03:27:27

问题


I want that if a user has ordered a meal, he can talk to the meal provider... and vice versa... Users can provide meals and order meals too, like on air bnb you can be a guest or a host (or both)

Exemples:

  1. Lets say we have Bob(buyer) who orders a meal from John(maker) I want that John and Bob can chat together
  2. John(buyer) orders a meal from Mike(maker), John and Mike can chat together.

conversations/index.html.erb

<% @users.each do |user| %>
  <%= link_to user.full_name , conversations_path(user_id: user), remote: true, method: :post %>
 <% end %>

user.rb (I have doubt in this model...)

  has_many :meals #Meals that the user offers
  has_many :received_orders, class_name: "Order" #The user receive an order
  has_many :placed_orders, through: :meals, class_name: "Order" #The user order a meal
  has_many :prepared_orders, through: :received_orders, class_name: "Meal", source: :meal #The user has prepared the order

  ####maybe this way below....TODO
  # has_many :meals
  # has_many :orders_as_a_customer, class_name: "Order"# same as: has_many :orders
  # has_many :orders_as_a_seller, through: :orders_as_a_customer, class_name: "Meal", source: :meal
  # has_many :orders, through: :meals

order.rb

class Order < ApplicationRecord
  before_save :calculate_price
  belongs_to :user
  belongs_to :meal

  has_many :notifications, as: :topic

  monetize :amount_cents, as: :amount

  def payment
    self.payment_status = true
    self.save
  end

  def calculate_price
    self.amount = (self.quantity * meal.price)
  end
end

Well I've followed this tutorial to create my chat, and I bet it's possible to adjust to my app to it...

conversation.rb

class Conversation < ApplicationRecord
  has_many :messages, dependent: :destroy

  belongs_to :sender, foreign_key: :sender_id, class_name: "User"
  belongs_to :recipient, foreign_key: :recipient_id, class_name: "User"

  validates :sender_id, uniqueness: { scope: :recipient_id }

  scope :between, -> (sender_id, recipient_id) do
    where(sender_id: sender_id, recipient_id: recipient_id).or(
      where(sender_id: recipient_id, recipient_id: sender_id)
    )
  end

  def self.get(sender_id, recipient_id)
    conversation = between(sender_id, recipient_id).first
    return conversation if conversation.present?

    create(sender_id: sender_id, recipient_id: recipient_id)
  end

  def opposed_user(user)
    user == recipient ? sender : recipient
  end
end

conversations_controller.rb

class ConversationsController < ApplicationController

  def create
    @conversation = Conversation.get(current_user.id, params[:user_id])

    add_to_conversations unless conversated?

    respond_to do |format|
      format.js
    end
  end

  def index
    session[:conversations] ||= []
    @users = User.all.where.not(id: current_user)
    @conversations = Conversation.includes(:recipient, :messages).find(session[:conversations])
  end

  def close
    @conversation = Conversation.find(params[:id])

    session[:conversations].delete(@conversation.id)

    respond_to do |format|
      format.js
    end
  end

  private

  def add_to_conversations
    session[:conversations] ||= []
    session[:conversations] << @conversation.id
  end

  def conversated?
    session[:conversations].include?(@conversation.id)
  end
end

my actual schema.rb

ActiveRecord::Schema.define(version: 20170629192651) do

  # These are extensions that must be enabled in order to support this database
  enable_extension "plpgsql"

  create_table "attachinary_files", force: :cascade do |t|
    t.string   "attachinariable_type"
    t.integer  "attachinariable_id"
    t.string   "scope"
    t.string   "public_id"
    t.string   "version"
    t.integer  "width"
    t.integer  "height"
    t.string   "format"
    t.string   "resource_type"
    t.datetime "created_at"
    t.datetime "updated_at"
    t.index ["attachinariable_type", "attachinariable_id", "scope"], name: "by_scoped_parent", using: :btree
  end

  create_table "categories", force: :cascade do |t|
    t.string   "name"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end

  create_table "conversations", force: :cascade do |t|
    t.integer  "recipient_id"
    t.integer  "sender_id"
    t.datetime "created_at",   null: false
    t.datetime "updated_at",   null: false
    t.integer  "order_id"
    t.index ["order_id"], name: "index_conversations_on_order_id", using: :btree
    t.index ["recipient_id", "sender_id"], name: "index_conversations_on_recipient_id_and_sender_id", unique: true, using: :btree
  end

  create_table "ingredients", force: :cascade do |t|
    t.string   "name"
    t.integer  "meal_id"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.index ["meal_id"], name: "index_ingredients_on_meal_id", using: :btree
  end

  create_table "meals", force: :cascade do |t|
    t.string   "menu_name"
    t.integer  "portion"
    t.date     "availability"
    t.datetime "created_at",   null: false
    t.datetime "updated_at",   null: false
    t.integer  "user_id"
    t.integer  "category_id"
    t.string   "images"
    t.string   "location"
    t.float    "latitude"
    t.float    "longitude"
    t.integer  "price"
    t.index ["user_id"], name: "index_meals_on_user_id", using: :btree
  end

  create_table "messages", force: :cascade do |t|
    t.text     "body"
    t.integer  "user_id"
    t.integer  "conversation_id"
    t.datetime "created_at",      null: false
    t.datetime "updated_at",      null: false
    t.index ["conversation_id"], name: "index_messages_on_conversation_id", using: :btree
    t.index ["user_id"], name: "index_messages_on_user_id", using: :btree
  end

  create_table "notifications", force: :cascade do |t|
    t.boolean  "read",       default: false
    t.string   "content"
    t.integer  "user_id"
    t.string   "topic_type"
    t.integer  "topic_id"
    t.datetime "created_at",                 null: false
    t.datetime "updated_at",                 null: false
    t.integer  "order_id"
    t.index ["order_id"], name: "index_notifications_on_order_id", using: :btree
    t.index ["topic_type", "topic_id"], name: "index_notifications_on_topic_type_and_topic_id", using: :btree
    t.index ["user_id"], name: "index_notifications_on_user_id", using: :btree
  end

  create_table "orders", force: :cascade do |t|
    t.text     "message"
    t.boolean  "payment_status", default: false
    t.integer  "quantity"
    t.integer  "user_id"
    t.integer  "meal_id"
    t.datetime "created_at",                     null: false
    t.datetime "updated_at",                     null: false
    t.integer  "amount_cents",   default: 0,     null: false
    t.json     "payment"
    t.index ["meal_id"], name: "index_orders_on_meal_id", using: :btree
    t.index ["user_id"], name: "index_orders_on_user_id", using: :btree
  end

  create_table "reviews", force: :cascade do |t|
    t.integer  "rating"
    t.text     "comment"
    t.integer  "meal_id"
    t.integer  "user_id"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.index ["meal_id"], name: "index_reviews_on_meal_id", using: :btree
    t.index ["user_id"], name: "index_reviews_on_user_id", using: :btree
  end

  create_table "users", force: :cascade do |t|
    t.string   "email",                  default: "", null: false
    t.string   "encrypted_password",     default: "", null: false
    t.string   "reset_password_token"
    t.datetime "reset_password_sent_at"
    t.datetime "remember_created_at"
    t.integer  "sign_in_count",          default: 0,  null: false
    t.datetime "current_sign_in_at"
    t.datetime "last_sign_in_at"
    t.inet     "current_sign_in_ip"
    t.inet     "last_sign_in_ip"
    t.datetime "created_at",                          null: false
    t.datetime "updated_at",                          null: false
    t.string   "provider"
    t.string   "uid"
    t.string   "facebook_picture_url"
    t.string   "first_name"
    t.string   "last_name"
    t.string   "token"
    t.datetime "token_expiry"
    t.string   "nickname"
    t.string   "avatar"
    t.index ["email"], name: "index_users_on_email", unique: true, using: :btree
    t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree
  end

  add_foreign_key "conversations", "orders"
  add_foreign_key "meals", "users"
  add_foreign_key "messages", "conversations"
  add_foreign_key "messages", "users"
  add_foreign_key "notifications", "orders"
  add_foreign_key "notifications", "users"
  add_foreign_key "orders", "meals"
  add_foreign_key "orders", "users"
  add_foreign_key "reviews", "meals"
  add_foreign_key "reviews", "users"
end

回答1:


Concluding from the comments, you'd need to have different models. Here are the ones that make sense to me:

class User < ApplicationRecord
  has_many :meals
  has_many :orders
  has_many :sent_messages, :class => 'ChatMessage', :foreign_key => 'sender_id'
  has_many :received_messages, :class => 'ChatMessage', :foreign_key => 'receiver_id'
end

class Meal < ApplicationRecord
  belongs_to :user
  belongs_to :order_item
end

class Order < ApplicationRecord
  belongs_to :user
  has_many :order_items
end

class OrderItem < ApplicationRecord
  belongs_to :order
  has_one :meal
end

class ChatMessage < ApplicationRecord
  belongs_to :sender, :class => 'User'
  belongs_to :receiver, :class => 'User'
end


来源:https://stackoverflow.com/questions/44826591/how-to-set-two-users-to-chat-together

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!