Postgres schema for users and approved users for a dating style app
Users see profiles of other users and tag approve
or reject
, ala Tinder or similar dating apps.
I am creating a Rails server with ActiveRecord and PostgreSQL on the server.
I look at a model User
, then a model Approval
that has user_id
and approved_id
.
statement:
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
This has the advantage of limiting the number of objects Approval
- there User
will be only 1 for each pair of s. However, I'm not sure how to efficiently query this schema.
When looking for actions approve
or reject
, for example, I need to manually check if the submitter matches user_id
user_id
or approved_id
user1_approval
or user2_approval
.
I am considering searching User
with a simple filter (age range for 10 years)
so in User
me:
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
Which is great for getting a list of your favorites. It also has the advantage of allowing api /approvals/:id/approve
and /approvals/:id/reject
.
I am wondering if it makes sense to use an API for example /users/:id/approve
and then this action generates Approval
accordingly. Each object Approval
has user_id
as well related_approval_id
, so it can refer to a reciprocal Approval
(where the target user matches the associated assertion user_id
).
create_table "approvals", force: :cascade do |t|
t.integer "user_id"
t.integer "approved_id"
t.integer "related_approval_id"
This makes a lot more rows in the database.
Hope this makes sense. I am looking for a good architectural solution for users who approve and reject each other, which allows me to make good requests, for example, only show User
which have current_user
not been approved and which have not been rejected by current_user.
source to share
Since a user can be “approved” or “rejected” by ala Tinder, it makes sense to call this model “Solution”. This is how I see it going.
User model
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
The user model represents any user of the application who decides that another user or another user will make a decision.
Decision making model
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
A solution is any interaction between users. One click of the right mouse button on the user. Another solution is to retaliate directly in front of another user. It is not presented as one coherent entity, but as two separate interaction "solutions".
Let me explain what the fields in the Solution mean:
- decision_maker_id - ID of the user who is scrolling
- decision_receiver_id - ID of the user who receives the swip
- approved - a boolean value that would be true if the napkin was valid and false if the napkin was abandoned.
- active - a boolean value that determines if this decision was still making the answer
In the Decision Model, you will need a before_save callback that will check if the decision to be saved has an already made decision for the responder. If this happens, you want the solution to stop being active so that it no longer appears in the feed. You can then notify users with whom they agree / disagree, or what you want to do at this point in your application.
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
In the user model, you can write methods that will find all active permissions / denials that exist.
scope :decisions, -> (id, approval_type) { where('decision_receiver_id = ? AND approved = ? AND active = true', approval_type) }
By calling this area with User.decisions(user_id, true)
, you can get all the approvals for the user. By calling this area with user.decisions(user_id, false)
, you can get all the deviations for the user.
You can also break this down into two separate areas, one for assertions and one for rejections.
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) }
Finally, you can do this with a method that is called on the User instance, so you don't need to pass the id parameter.
# 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
And you can call this on a user instance for example user.get_decisions(true)
.
source to share