用户查看其他用户的个人资料,并标记approve
或reject
、ala Tinder或类似的约会应用程序。
我正在用ActiveRecord&后端的PostgreSQL。
我正在考虑有一个User
模型,然后是一个有user_id
和approved_id
的Approval
模型。
批准:
create_table "approvals", force: :cascade do |t|
t.integer "user_id"
t.integer "approved_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.datetime "user1_approval"
t.datetime "user2_approval"
t.datetime "denied_at"
end
class User
has_many :approvals
has_many :approved, through: :approvals
has_many :inverse_users, class_name: "Approval", foreign_key: "approved_id"
has_many :inverse_approvals, through: :inverse_users, source: :user
class Approval
def self.user_approval(user1, user2)
sorted = [user1, user2].sort_by { |u| u.name}
Approval.find_or_create_by(user: sorted[0], approved: sorted[1])
end
这样做的优点是限制了Approval
对象的数量——每对User
对象只有1个。然而,我不确定如何使用此模式有效地进行查询。
例如,当查找approve
或reject
动作时,我必须手动检查提交的user_id
是否与user_id
或approved_id
匹配,以适当地设置user1_approval
或user2_approval
。
我正在考虑通过一个简单的过滤器(年龄范围在10年内(查找User
因此在User
中我有:
def self.eligible(user)
users = User.where('age >= ? AND age <= ? AND id != ?', user.lowest_eligible_age,user.maximum_eligible_age, user.id).limit(20)
approvals = []
users.each do |u|
approvals.push(Approval.user_approval(user, u ))
end
approvals.reject! { |a| a.denied_at}
approvals
end
这对于获得合格用户的入围名单非常有用。它还具有允许CCD_ 18&/approvals/:id/reject
。
我想知道使用像/users/:id/approve
这样的API,然后让该操作相应地生成Approval
是否更有意义。每个Approval
对象将具有user_id
和related_approval_id
,因此它可以链接到相互的Approval
(其中目标用户与链接的批准的user_id
相同(。
create_table "approvals", force: :cascade do |t|
t.integer "user_id"
t.integer "approved_id"
t.integer "related_approval_id"
这样做会在数据库中产生更多的行。
我希望这是有道理的。我正在寻找一个好的架构解决方案,以用户批准&相互拒绝,这允许我进行良好的查询,比如只显示CCD_ 28尚未批准和尚未拒绝current_user的CCD_。
因为用户可以被Tinder"批准"或"拒绝",所以将此模型称为Decision更有意义。以下是我对这件事的看法。
用户模型
create_table "users", force: :cascade do |t|
t.integer "id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "age"
...etc...
end
用户模型代表应用程序的任何用户,他们将对另一个用户做出决定或另一用户将对其做出决定。
决策模型
create_table "decision", force: :cascade do |t|
t.integer "id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "decision_maker_id"
t.integer "decision_receiver_id"
t.boolean "approved"
t.boolean "active"
...etc...
end
决策表示用户之间的任何交互。向右滑动用户是一个决定。另一个决定是对方用户向右滑动。这不是作为一个整体对象来表示的,而是作为两个独立的"决策"交互来表示的。
让我解释一下Decision中的字段是什么意思:
- decision_maker_id-进行刷单的用户的id
- decision_rereceiver_id-接收刷单的用户的id
- approved-一个布尔值,如果向右滑动则为true,如果向左滑动则为false
- active-一个布尔值,用于确定此决策是否已做出回复决策
在Decision模型中,您需要一个before_save回调来检查正在保存的决策是否已经有对应的回复决策。如果是这样,那么你会想让这个决定不再有效,这样它就不会再出现在提要上了。然后,你可以在应用程序中通知用户他们同意/不同意,或者你想做的任何事情。
before_save: check_for_existing_reply
def check_for_existing_reply
# if there is a decision object with this decision_maker_id and this
# decision_receiver_id but in opposite fields then you know there is a reply
# and you can take some action here
end
在用户模型中,您可以编写方法来查找所有存在的活动批准/拒绝。
scope :decisions, -> (id, approval_type) { where('decision_receiver_id = ? AND approved = ? AND active = true', approval_type) }
通过使用User.decisions(user_id, true)
调用该作用域,您可以获得用户的所有批准。通过用user.decisions(user_id, false)
调用该作用域,您可以获得用户的所有拒绝。
您也可以将其分解为两个独立的范围,一个用于批准,另一个用于拒绝。
scope :approvals, -> (id) { where('decision_receiver_id = ? AND approved = ? AND active = true', true) }
scope :rejections, -> (id) { where('decision_receiver_id = ? AND approved = ? AND active = true', false) }
最后,您可以将其作为在User实例上调用的方法,这样您就不必传入id参数。
# where decision = true would mean approvals and decision = false would mean rejections
def get_decisions(decision)
return User.where('decision_receiver_id = self.id AND approved = decision AND active = true') }
end
您可以在像user.get_decisions(true)
这样的User实例上调用它。