Question

I am creating a location-based application that lists reading programs on a map. Each program has many age_groups (through program_age_groups) and has many locations (through program_locations). For the search results, I need to list each program_location matching the user's criteria. I created a search model, which also has many age_groups through search_age_groups. My question is, how do I filter the program locations based on its associated programs' age_group_ids? I can get it to work by doing something like this in the search model:

program_locations = ProgramLocation.all.includes(program: :age_groups)
program_locations = program_locations.where(age_groups: self.age_group_ids)

However, this creates a join statement on age_group_ids, and when I loop through the program locations and list the program's details, only the age groups matching the search age groups show up. Even if the program has other age groups, they will only show up if the user selects those in the search, or if the age groups field is blank on the search.

EDIT: Clarification

For example, say Program 1 has age_groups 0-2 and 3-5, and Program 2 has age_group 6-10. A user does a search and selects only age_group 0-2. When I display the results, it will correctly filter out Program 2, but it will display:

Program 1 Age Groups: 0-2

when it should display

Program 1 Age Groups: 0-2, 3-5

Any ideas? This seems like a common problem, and I've run into something similar in the past, but I can't seem to find a straight-forward solution. I tried using reject, but that does not return an activerecord relation, and I need to add a pagination call at the end of the query.

Was it helpful?

Solution

You could scope them like so:

class Program
   has_many :program_age_groups
   has_many :age_groups, through: :program_age_groups
   has_many :program_locations
   has_many :locations, through: :program_locations

   scope :by_age_group,->(age_group){ 
                          program_ids = program_age_groups.where(age_group: age_group).pluck(:program_id)
                          where(id: program_ids)
                         }
   scope :by_location,->(location){
                          program_ids = program_locations.where(location: location).pluck(:program_id)
                          where(id: program_ids)
                          }

end

Then call with

age_groups = ['0-2']
Program.by_age_group(age_groups)

This will return an ActiveRecord::Relation[] of Programs with the specified age groups. Or

location = "Some location"
age_groups = ['0-2']
Program.by_location(location).by_age_group(age_groups)

scopes are a very powerful tool and I find them especially useful for searching as you can chain them together nicely while preserving readability.

Update

class ProgramLocation
    belongs_to :program
    belongs_to :location

    scope :by_age_group,->(age_group){
          program_ids = Program.by_age_group(age_group).pluck(:id)
          where(program_id: program_ids)
         }
    scope :by_location,->(location){
          location_ids = Location.where(name: location).pluck(:id)
          where(location_id: location_ids
          }

end

This assumes that your location as an attribute name that you are searching for in the scope not sure if this is true but should get you somewhere close.

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