Ruby on rails 检查两个或多个特定用户之间是否已存在对话,其中用户对话具有HABTM关联
用户拥有并属于许多对话。一个对话拥有并属于许多用户,并且有许多消息。消息属于用户,也属于对话 一个非常简单的关系模型,最初工作得很好,但现在当我重构它以处理组消息(即两个以上用户之间的消息)时让我头疼 我以前只对HABTM关联进行了肤浅的研究,不知道如何检查给定用户阵列之间是否已经存在对话。此检查将在控制器中进行,可能通过模型中定义的范围进行。编辑:此检查可能仅适用于两个用户之间的对话。比如说,Ruby on rails 检查两个或多个特定用户之间是否已存在对话,其中用户对话具有HABTM关联,ruby-on-rails,ruby,ruby-on-rails-3,has-and-belongs-to-many,Ruby On Rails,Ruby,Ruby On Rails 3,Has And Belongs To Many,用户拥有并属于许多对话。一个对话拥有并属于许多用户,并且有许多消息。消息属于用户,也属于对话 一个非常简单的关系模型,最初工作得很好,但现在当我重构它以处理组消息(即两个以上用户之间的消息)时让我头疼 我以前只对HABTM关联进行了肤浅的研究,不知道如何检查给定用户阵列之间是否已经存在对话。此检查将在控制器中进行,可能通过模型中定义的范围进行。编辑:此检查可能仅适用于两个用户之间的对话。比如说, A conversation between User 1 and User 2 already e
A conversation between User 1 and User 2 already exists.
User 1 sends a message to User 2 via the "Compose New Message" page.
The preexisting conversation is found and selected, and the new message is inserted into it.
对
A conversation between User 1, User 2, and User 3 already exists.
User 1 sends a message to User 2 and User 3 via the "Compose New Message" page.
A new conversation is made, rather than searching for a pre-existing conversation.
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
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/迁移/创建\对话\用户\加入
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
更新:尝试了@DavidStosik的解决方案,但在方法作用域上出现以下名称错误:
Started POST "/conversations" for 127.0.0.1 at 2015-09-10 16:53:51 -0400
Processing by ConversationsController#create as */*
Parameters: {"user_ids"=>"1 2"}
[1m[35mUser Load (1.0ms)[0m SELECT "users".* FROM "users" WHERE "users"."id" = 1 ORDER BY "users"."id" ASC LIMIT 1
Completed 500 Internal Server Error in 3ms
NameError (undefined local variable or method `scoped' for #<Class:0x5afc2b8>):
app/models/conversation.rb:25:in `block in <class:Conversation>'
app/controllers/conversations_controller.rb:13:in `create'
app/controllers/application_controller.rb:19:in `user_time_zone'
试试这样的
class Conversation < ActiveRecord::Base
scope :between, ->(users) do
base = all
conditions = []
users.each.with_index do |user, i|
base = base
.joins("JOIN conversations_users AS cu#{i} ON cu#{i}.conversation_id = conversations.id")
cu_table = Arel::Table.new("cu#{i}")
if condition
condition = condition.and cu_table[:id].eq(user.id)
else
condition = cu_table[:id].eq(user.id)
end
end
base.where(condition)
end
end
但是,同时选择太多的用户会使查询变得庞大。相对容易编码的实现依赖于选择对话,其中存在三个用户对话连接记录,其中用户ID是您感兴趣的 您确实需要访问用户和对话之间的连接表才能使其高效,但逻辑如下:
Conversation.where(:id =>
UserConversation.where(:user_id => [array of user ids]).
group(:conversation_id).
having("count(*) = ?", [array of user ids].size).
pluck(:conversation_id))
未检查语法我认为,您可能可以将连接删除到那里的用户表,并且仅依赖于对话用户表。不幸的是,我在作用域方法上遇到了一个名称错误。我已将回溯添加到我的原始帖子中,因为注释不保留换行符,看起来像是。@KalynHorn Try all而不是scoped。您希望对话仅在用户之间进行,还是对话还可以包括其他人?仅在这些特定用户之间。啊!看起来是一个非常优雅的解决方案。我试图研究如何访问联接表,但找不到明确的答案。可能是因为它很简单。我必须为表格制作模型吗?更新:我找到了解释。如果我使用你的方法,用户对话是否会有一种“有很多:通过”的关系?我不知道有什么区别。我将继续调查。双重更新:啊。。。。这样做的问题是,事情正在写入联接表中。。。。。。。然后立即删除。。。我不知道为什么。是的,我认为很多人都支持这一点。您还可以将其用于与该用户和对话相关的属性,比如他们第一次加入时。
Conversation.where(:id =>
UserConversation.where(:user_id => [array of user ids]).
group(:conversation_id).
having("count(*) = ?", [array of user ids].size).
pluck(:conversation_id))