Use scope of a belongs_to association to scope in the first model - Ruby on Rails
Asked Answered
A

2

5

Problem

Lets say I have two Models with a has_many-belongs_to relation. The has_many has a scope defined and an integer attribute named grade.

class Parent < ApplicationRecord
  has_many :children
  scope :great, -> (min_grade) {where("grade > :grade", grade: min_grade)}
end

class Child < ApplicationRecord
  belongs_to :parent
end

I want to create an scope on the child model, that uses the scope of the parent model.

Is there anyhow so that I can use the definition of scope on Parent?

Current solution

The way I'm doing it right now is

class Child < ApplicationRecord
  belongs_to :parent
  scope :wit_great_parent, -> (min_grade) {
        join(:parent).where("grade > :grade", grade: min_grade)}
end

However, I'm copying the where clause in both places.

Question

Is there anyhow to call the Parent scope from the child model?

Alacrity answered 14/11, 2016 at 16:51 Comment(2)
the child has only one parent, so i don't think it makes much sense to scope a single object :/ perhaps return nil if parent.grade > min_grade ?Blandish
I want to return all the Children that have a parent with greater grade. I don't want to get all of the children and check one by one by the "if" that you propose.Alacrity
E
7

If you are just looking to merge in the scope then

class Child < ApplicationRecord
  belongs_to :parent
  scope :with_great_parent, -> (min_grade) {joins(:parent).merge(Parent.great(min_grade))}
end

should handle this for you. The SQL generated will be similar to

SELECT * 
FROM children 
  INNER JOIN parents ON children.parent_id = parents.id
WHERE 
  parents.grade > --Whatever value you pass as min_grade

See ActiveRecord::SpawnMethods#merge for more information

Endoparasite answered 14/11, 2016 at 18:51 Comment(1)
Yes! thats it! ThanksAlacrity
L
1

Hmm, perhaps, you just need to put parents. before grade > :grade query in Child's scope. And you misspelled joins method.

Try use scope on Child model like so:

class Child < ApplicationRecord
  belongs_to :parent
  scope :wit_great_parent, -> (min_grade) {
        joins(:parent).where("parents.grade > :grade", grade: min_grade)
  }
end
Lakitalaks answered 14/11, 2016 at 17:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.