ActiveRecord::Relation issue

Hi, everyone.

Yesterday found an interesting issue in scope method. Let`s say, you have next model structure:

Model A --has_many-> Model B --has_many-> Model C --has_many-> Model_D

Model D has some attribute, let`s say, 'status' ENUM('opened', 'closed').

In Model A I would like to take all records, where Model D`s status is opened. This is a little bit confusing.

Here is an example. We have a project. A project has many tasklists. Tasklist has many tasks. I would like take all projects, which have one or more tasks opened. I hope, there should be any possibility to call in controller just active_projects = Project.all.active.

I would appreciate any help.

Max Reznichenko

I guess I have to chalk to up to another "I didn't know you could do that". I'll also admit I have no idea how efficient this is.

I've used a technique where I query a belongs_to table with the ids of a has_many related table. In my test I have   Assessments has_many -> Questions has_many -> Answers

I'd do something like   answer_ids = Answer.where(:requires_other => true).select(:question_id).map(&:question_id)   # @foo.map(&:id) is shorthand for @foo.map{|i| i.id}, which gets array of ids   question_ids = Question.where(:id => answer_ids).select(:assessment_id).map(&:assessment_id)   @assessments = Assessment.where(:id => question_ids)

Or, if you want one big hard to read statement!

@assessments = Assessment.where(:id => Question.where(:id => Answer.where(:requires_other => true).select(:question_id).map(&:question_id)).select(:assessment_id).map(&:assessment_id))

Someone else will have to chime in on how efficient or inefficient this is. My last project was on a database that was very reliant on "sets" and this is the closest thing I've found in rails to that concept.

Steve

Someone else will have to chime in on how efficient or inefficient this is. My last project was on a database that was very reliant on "sets" and this is the closest thing I've found in rails to that concept.

Just To clarify the last statement, the Database environment was 4D and in 4D you'd do

QUERY([Answers];[Answers]requires_other = true) RELATE ONE SELECTION([Answers];[Questions]) RELATE ONE SELECTION([Questions];[Assessments])

Don't know if there is an equivalent approach in Rails.

Steve

Hi, everyone.

Yesterday found an interesting issue in scope method. Let`s say, you have next model structure:

Model A --has_many-> Model B --has_many-> Model C --has_many-> Model_D

Are the reverse relationships has_many or belongs_to?

Colin

Colin Law wrote in post #954645:

Are the reverse relationships has_many or belongs_to?

Colin

Yes, sure. A <--belongs_to- B <--belongs_to- C <--belongs_to- D

2Steve.

Here you have a right solution, but this code should be written in controller. In this case, I could easily run through all records and calculate the Model A`s state.

Anyway, for 3 model structure there is actually a solution. Here it is: #Model C definition belongs_to :model_b

#Model B definition has_many :model_c belongs_to :model_a

#Model A definition has_many :model_b -->has_many :model_c, :through => :model_b

Max Reznichenko

Colin Law wrote in post #954645:

Are the reverse relationships has_many or belongs_to?

Colin

Yes, sure. A <--belongs_to- B <--belongs_to- C <--belongs_to- D

2Steve.

Here you have a right solution, but this code should be written in controller. In this case, I could easily run through all records and calculate the Model A`s state.

Anyway, for 3 model structure there is actually a solution. Here it is: #Model C definition belongs_to :model_b

#Model B definition has_many :model_c belongs_to :model_a

#Model A definition has_many :model_b -->has_many :model_c, :through => :model_b

I have not tried it but can you then say has_many :model_d, :through -> :model_c

If you can then I think you can just find A where a.d.state is whatever.

Colin

At the end of the day, the most important thing is that it works. However, I think we should try to get the database do the work. I'll apologize in advance that this example is rails2.

# Project -> TaskList -> Task Project.all(:group => "projects.id", :joins => {:task_lists => :task}, :conditions => "tasks.status = 'open'")

This results is a list of projects that have open tasks.

Luke

Luke Cowell wrote in post #954803:

At the end of the day, the most important thing is that it works. However, I think we should try to get the database do the work. I'll apologize in advance that this example is rails2.

# Project -> TaskList -> Task Project.all(:group => "projects.id", :joins => {:task_lists => :task}, :conditions => "tasks.status = 'open'")

This results is a list of projects that have open tasks.

Luke

Thanks a lot, Luke. This is exactly, what I meant.

Actually, there is next structure:

User -> Project -> Tasklist -> Task

Thanks to Luke, I wrote next scope in the model:

class Project < ActiveRecord::Base   has_and_belongs_to_many :users   has_many :tasklists   belongs_to :user

  def self.active     all(:group => 'projects.id', :joins => {:tasklists => :tasks}, :conditions => "tasks.status = 'open'")   end end

And now the call User.first.projects.active returns all the projects with active tasks.

Max Reznichenko

Colin Law wrote in post #954800:

belongs_to :model_a

#Model A definition has_many :model_b -->has_many :model_c, :through => :model_b

I have not tried it but can you then say has_many :model_d, :through -> :model_c

If you can then I think you can just find A where a.d.state is whatever.

Why not use the nested_has_many_through plugin?

Colin

Best,

At the end of the day, the most important thing is that it works. However, I think we should try to get the database do the work. I'll apologize in advance that this example is rails2.

# Project -> TaskList -> Task Project.all(:group => "projects.id", :joins => {:task_lists => :task}, :conditions => "tasks.status = 'open'")

This results is a list of projects that have open tasks.

Luke

Still not a lot out there on rails3 finders/arel examples. Is this the rails3 version of the above?

Project.group(:id).joins(:task_lists => :tasks).where(:tasks => {:status => 'open'})

Seemed to work in my assessments example

Assessment.group(:id).joins(:questions => :answers).where(:answers => {:requires_other => true})