1

I've got two models:

class Continent < ActiveRecord::Base
  has_many :countries
end

class Country < ActiveRecord::Base
  belongs_to :continent
end

I created controller like:

class ContinentsController < ApplicationController
  def index
    @continents = Continent.all
    render json: @continents
  end
end

and serializer:

class ContitnentSerializer < ActiveModel::Serializer
  attributes :name, :countries
end

Here my issue begins. I'd like to serialize only countries with given condition where value comes from HTTP GET params. E.g country inside serializer should be displayed only if population is more than params[:population]. The problem is inside serializer we don't have access to params to examine that.

[
 {
  name: 'Europe'
  countries: [ 
    {
      name: 'Italy',
      population: 1000000 
    }
  ]
 },
 {
  name: 'Africa'
  countries: [ 

  ]
 }
]

I've tried to join table with condition but it seems be not working.

@continents = Continent.all.joins("LEFT JOIN countries ON countries.continent_id = continents.id AND countries.population > #{params[:population]}")
mike927
  • 682
  • 1
  • 8
  • 25
  • You could pass a parameter to the serializer from the controller. More details here: http://stackoverflow.com/a/26780514/1466095 – Zero Fiber Apr 13 '16 at 12:44

3 Answers3

1

Create a scope and call the scope with param value from controller:

scope :population_more_than, ->(population) {all.joins("LEFT JOIN countries ON countries.continent_id = continents.id AND countries.population > ?", population)}

Now call it from controller instead of Continent.all

Continent.population_more_than(params[:population])
Babar Al-Amin
  • 3,939
  • 1
  • 16
  • 20
  • seems to return all countries instead of reduced by condition – mike927 Apr 13 '16 at 13:04
  • Umm, not exactly sure. You can try to interpolate `population` in the query, without passing it as param at the end. ANother thing you may try, wrap `population` in a array like this: `scope :population_more_than, ->(population) {all.joins("LEFT JOIN countries ON countries.continent_id = continents.id AND countries.population > ?", [population])}` – Babar Al-Amin Apr 13 '16 at 13:35
  • it's not related with interpolation. I just used it appropriate otherwise I would get some error. I am wondering if that SQL query do what we expect. – mike927 Apr 13 '16 at 13:45
0

You can try

@continents = Continent.all
@continents.num_population = params[:population]
render json: @continents.to_json(methods: :countries_with_population_gt)

in your Continent model

attr_accessor :num_population

def countries_with_population_gt(num_population=0)
  countries.where('population > ?', @num_population)
end
Abdoo Dev
  • 1,216
  • 11
  • 16
0

Basically, you need to select only Continents that fall under specific rule. If this is a frequently used filter, then I would go with the Babar's suggestion and create a scope.

If this is a one time selection, then I prefer simply do filtering right there without cluttering up my models with non-frequently used scopes.

Continent.joins(:countries).where("countries.population > :population", population: params[:population])

# Or event shorter
Continent.joins(:countries).where("countries.population > :population", params)
Uzbekjon
  • 11,655
  • 3
  • 37
  • 54