我想找到一个用户的所有的convos
那里是不是connect
我有一个convos
表,带有sender_id
和recipient_id
,这两个都是对用户ID的引用
# app/models/user.rb
has_many :convos, ->(user) {
unscope(:where).where("sender_id = :id OR recipient_id = :id", id: user.id)
}
请注意,convo可以属于sender_id或receive_id的用户。
# app/models/convo.rb
class Convo < ApplicationRecord
belongs_to :sender, :foreign_key => :sender_id, class_name: 'User'
belongs_to :recipient, :foreign_key => :recipient_id, class_name: 'User'
has_many :msgs, dependent: :destroy
validates_uniqueness_of :sender_id, :scope => :recipient_id
scope :involving, -> (user) do
where("convos.sender_id =? OR convos.recipient_id =?",user.id,user.id)
end
scope :between, -> (sender_id,recipient_id) do
where("(convos.sender_id = ? AND convos.recipient_id =?) OR (convos.sender_id = ? AND convos.recipient_id =?)", sender_id,recipient_id, recipient_id, sender_id)
end
end
Connect
表中有requestor_id
和requestee_id
都是对用户ID的引用。连接模型
class Connect < ApplicationRecord
belongs_to :requestor, :foreign_key => :requestor_id, class_name: 'User'
belongs_to :requestee, :foreign_key => :requestee_id, class_name: 'User'
scope :between, -> (requestor_id,requestee_id) do
where("(connects.requestor_id = ? AND connects.requestee_id =?) OR (connects.requestor_id = ? AND connects.requestee_id =?)", requestor_id,requestee_id, requestee_id, requestor_id)
end
end
我想找到一个用户的所有的convos
那里是不是connect
我已经尝试过类似的方法:
user = User.first
user.convos.where.not(Connect.between(self.requestor_id, self.requestee_id).length > 0 )
# NoMethodError (undefined method `requestor_id' for main:Object)
user.convos.where.not(Connect.between(convo.requestor_id, convo.requestee_id).length > 0 )
# undefined local variable or method `convo' for main:Object
然后,我尝试完全不引用用户,而只是尝试在没有连接的情况下获得所有convo。
Convo.where("Connect.between(? ,?) < ?)", :sender_id, :recipient_id, 1)
# ActiveRecord::StatementInvalid (SQLite3::SQLException: near "between": syntax error: SELECT "convos".* FROM "convos" WHERE (Connect.between('sender_id' ,'recipient_id') < 1)))
Convo.where("Connect.between(? ,?) < ?)", self.sender_id, self.recipient_id, 1)
# NoMethodError (undefined method `sender_id' for main:Object)
在不存在连接的情况下获取所有用户需求的最佳方法是什么?
更新
这是可行的,而且是我要寻找的,但是显然这很浪费,我想了解如何在一次通话中获得此功能。
@og_connections = []
current_user.convos.each do |convo|
if Connect.between(convo.sender_id, convo.recipient_id).length === 0
@og_connections.push(current_user.id === convo.sender_id ? convo.recipient_id : convo.sender_id)
end
end
@connections = User.select(:id, :first_name, :slug).where(id: @og_connections, status: 'Active')
如果你正在寻找的只是current_user
,你会想用自己开始convos
,做一个左加盟connects
,并选择其中的行connects
为NULL
。使用您的表设置,我们将必须对可能的user_id组合进行手动连接:
current_user.convos.joins("
LEFT JOIN connects ON
(connects.requestor_id = convos.sender_id AND connects.requestee_id = convos.recipient_id)
OR
(connects.requestor_id = convos.recipient_id AND connects.requestee_id = convos.sender_id)
").where(connects: {id: nil})
左边的联接为您提供了与convo相同的两个用户之间的任何连接,current_user
因为我们从开始就必须涉及current_user.convos
。从那里,我们筛选下降到仅其中的行connects
字段NULL
,让我们用行,它一康沃不具有匹配的连接。
在Rails应用程序中,大量的原始SQL有点代码味道,这是因为我们试图在此处按原样设置模型来执行这些操作。我建议重构数据模型以简化查询。我想到两个想法:
OR
s。也就是说,无论何时connect
在用户1和用户2之间创建一个,也要在用户2和用户1之间创建一个。更多簿记,因为您还必须一起销毁和编辑它们。但是它可以让你。定义没有所有障碍的简单关联。UserPair
使用user_1_id
和创建一个模型user_2_id
,其中user_1_id
始终设置为两个用户ID中的较低者。这样一来,convo可以更容易地通过user_pair_id
,UserPair
罐has_many :convos
和来识别has_many: connects
,并且您可以将之间的直线连接起来convos -> user_pairs -> connects
。2中的模型看起来像
class UserPair < ApplicationRecord
belongs_to :user_1, class_name: "User"
belongs_to :user_2, class_name: "User"
before_save :sort_users
scope :between, -> (user_1_id,user_2_id) do
# records are always saved in sorted id order, so sort before querying
user_1_id, user_2_id = [user_1_id, user_2_id].sort
where(user_1_id: user_1_id, user_2_id: user_2_id)
end
# always put lowest id first for easy lookup
def sort_users
if user_1.present? && user_2.present? && user_1.id > user_2.id
self.user_1, self.user_2 = user_2, user_1
end
end
end
class Convo < ApplicationRecord
belongs_to :sender, :foreign_key => :sender_id, class_name: 'User'
belongs_to :recipient, :foreign_key => :recipient_id, class_name: 'User'
belongs_to :user_pair
before_validation :set_user_pair
scope :involving, -> (user) do
where("convos.sender_id =? OR convos.recipient_id =?",user.id,user.id)
end
# since UserPair records are always user_id sorted, we can just use
# that model's scope here without need to repeat it, using `merge`
scope :between, -> (sender_id,recipient_id) do
joins(:user_pair).merge(UserPair.between(sender_id, recipient_id))
end
def set_user_pair
self.user_pair = UserPair.find_or_initialize_by(user_1: sender, user_2: recipient)
end
end
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句