Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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?

like image 750
Mateu Avatar asked Nov 14 '16 16:11

Mateu


People also ask

How would you choose between Belongs_to and Has_one?

They essentially do the same thing, the only difference is what side of the relationship you are on. If a User has a Profile , then in the User class you'd have has_one :profile and in the Profile class you'd have belongs_to :user . To determine who "has" the other object, look at where the foreign key is.

What is the use of scope in Rails?

Scopes are used to assign complex ActiveRecord queries into customized methods using Ruby on Rails. Inside your models, you can define a scope as a new method that returns a lambda function for calling queries you're probably used to using inside your controllers.

What is scope in ruby model?

Scopes are custom queries that you define inside your Rails models with the scope method. Every scope takes two arguments: A name, which you use to call this scope in your code. A lambda, which implements the query.


1 Answers

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

like image 66
engineersmnky Avatar answered Sep 18 '22 03:09

engineersmnky