yzhan
yzhan

Reputation: 170

Rails ActiveRecord querying

So I have the following three models: Assignment.rb, Submission.rb, User.rb

And here are the relationships:

class Assignment
  has_many :submissions
end

class Submission
  belongs_to :assignment
  belongs_to :user
  # submission has a boolean column called submitted with val true or false
end

class User
  has_many submissions
end

I want to know how can I query the assignments that a user has not submitted (in a clean way)? If a user submits an assignment, a new submission for that assignment and user will be created.

Not sure if I provided enough info for anyone to answer, so please comment if anything else is needed.Thx!

Upvotes: 0

Views: 71

Answers (3)

moveson
moveson

Reputation: 5213

The logic that @Norly Canarias is using is correct, but I would alter it to use methods on the User class, and I would also modify it to make it database-agnostic (for example, using 'submissions.submitted = true' will not work at all in Postgres).

class User < ApplicationRecord
  has_many :submissions
  has_many :assignments, through: :submissions

  def submitted_assignments
    assignments.where(submissions: {submitted: true})
  end

  def unsubmitted_assignments
    Assignment.where.not(id: submitted_assignments)
  end
end

I have tested this and it works as expected. For a user who has a Submission for Assignment 1 with submitted == true, and who has a Submission for Assignment 2 with submitted == false, and assuming there are two more Assignments (3 and 4) for which no Submission exists, you will get:

>> user.submitted_assignments.ids
#=>[1]
>> user.unsubmitted_assignments.ids
#=>[2, 3, 4]

Upvotes: 2

Norly Canarias
Norly Canarias

Reputation: 1736

I think something like this could work (I haven't tested though):

class Assignment
  has_many :submissions
end

class Submission
  belongs_to :assignment
  belongs_to :user
end

class User
  has_many :submissions
  has_many :assignments, through: :submissions
end

user         = User.first
submitted    = user.assignments.where('submissions.submitted = true')
not_submitted = Assignment.where.not(id: submitted)

You can also make it a scope

class Assignment
   has_many :submissions
   scope :not_submitted_by_user, ->(user) do
     where.not(id: user.assignments.where('submissions.submitted = true'))
   end
end

user = User.first    
not_submitted = Assignment.not_submitted_by_user(user)

Upvotes: 1

yassine2020
yassine2020

Reputation: 831

To get all the Assignments that are not from a specific user

@assignments = Assignment.where.not(user_id: user_id)

A clean way to do it is to create a scope in the Assignment Model

class Assignment
  has_many :submissions

  scope :not_from_user, ->(user_id) {where.not(user_id: user_id) }
end

And then calling

 @assignments = Assignment.not_from_user 1

Upvotes: 0

Related Questions