Question

Model A has_many model_bs.

Model B belongs_to model_a and model_c.

Model C has_many model_bs and can by of type black or white.

I want to pull all records of model A, which have model Bs, that belong to model C of type black. So far I could pull all records of model B, which belong to model C of type black, like so:

ModelB.joins(:model_c).where("model_c.type = 'black'")

This returns an ActiveRecord::Relation::ActiveRecord_Relation_ModelB, but now I need something like:

records = ModelB.joins(:model_c).where("model_c.type = 'black'")
Model_A.where model_b: records

which doesn't work for obvious reasons.

Another thing I tried was:

Model_A.includes(:model_bs).includes(model_c).where("model_c.type = 'black'")

but this produces the error:

ActiveRecord::ConfigurationError:
       Association named 'model_c' was not found on ModelA; perhaps you misspelled it?

So how do I do this? I would also like to understand the principle of querying, when you have a lot of chained models and want to retrieve records of model X, based on attribute of model Y, with model Y being n levels away from model X.

Was it helpful?

Solution

I think you need joins and not includes since you only want one model as a result.

Model_A.joins(model_bs: :model_c).where("model_cs.type = 'black'").references(:model_cs)

because modelA has many modelbs and modelC has many modelbs

OTHER TIPS

You made a typo: includes(model_c) should be includes(:model_c) and this is where the error Association named 'model_c' was not found on ModelA came from.

One way to get your query could be:

Model_A.includes(:model_bs, :model_cs).where("model_cs.type = 'black'").references(:model_cs)

Also in your models you could link Model_A and Model_C directly by:

In Model_A

has_many :model_cs, :through => :model_bs

In Model_C

has_many :model_as, : through => :model_bs

Just for the record - since I constantly got the error that no model_c attribute is defined on ModelA I figured that in ModelA.includes(:model_bs).includes(:model_c) it searches for a direct relation between ModelA and ModelC. So I did this - the common entity between ModelA and ModelC is ModelB, thus:

ModelB.includes(:model_a).included(:model_c).where("my_string_criteria")

Although this returns instances of ModelB and not of ModelA, as I originally wanted, this was not a problem, as I only needed the values from one field of ModelA and was going to use pluck anyway. So I used pluck on the above mentioned relation instead and still got what I was looking for. But xlembouras was more precise and more efficient so I went with his suggestion.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top