简体   繁体   中英

ActiveRecord has_one with a dynamic scope

I have this

class Student
  has_many :assignments
end

class Assignment
  belongs_to :student
  belongs_to :book
end

class Book
  has_many :assignments
end

To find the student's "Harry Potter" assignment, I am doing this

@student.assignments.find_by_book_id(Book.find_by_name('Harry Potter'))

Is there a way to make this into a has_one association for the Student model?

Something like this (pseudo-code here)

class Student
  has_many :assignments
  has_one  :harry_potter_assigment, -> { where book_id: Book.find_by_name('Harry Potter') }, class: 'Assignment'
end

If not with a has_one , what is a better way?

If I'm not wrong, the following should work

#student.rb
class Student
  has_many :assignments
  has_one :harry_potter_assigment, -> { where(book_id: Book.find_by_name('Harry Potter').id }, class_name: "Assignment"
end

You can try to define it like this:

class Student < ActiveRecord::Base
  has_many :assignments

  def assignments_named(book_name)
    self.assignments.join(:book).where("books.name=?",name)
  end
end

Now querying:

student = Student.first
student.assignments_named('Harry Potter')

produces the following SQL:

SELECT "assignments".* FROM "assignments"
INNER JOIN "books" ON "books"."id" = "assignments"."book_id"
WHERE "assignments"."student_id" = 1 AND (books.name='Harry Potter')

It's not has_one relation though. There might be zero, one or more assignments for given student and book 'Harry Potter'.

If you want to make book's title dynamic, you can do the following:

class Student
  has_many :assignments
  has_many :books, through: :assignments

  def book_by_name(book_name)
    books.find_by!(name: book_name)
  end
end

And call it this way:

ron = Student.find_by(name: 'Ron')
harry_potter_book = ron.book_by_name('Harry Potter')

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM