Search code examples
ruby-on-rails-3includehas-many-throughnamed-scope

Need to bring back information on intermediate model with terminal model on Rails has_many through


I have the following models:

school.rb

class School < ActiveRecord::Base

  has_many :offers
  has_many :players, :through => :offers

  has_many :teammembers, :class_name => 'Offer', :conditions => ["on_roster = \'t\'"]
  has_many :teamplayers, :through => :teammembers, :source => :player

player.rb

class Player < ActiveRecord::Base

  has_many :offers, :dependent => :destroy

  scope :sr, lambda { 
    where("(players.year = ? and players.redshirt = 't') or (players.year = ? and players.redshirt = 'f')", (Time.now + 8.months - 5.years).year, (Time.now + 8.months - 4.years).year)

}

offer.rb

class Offer < ActiveRecord::Base
    belongs_to :school
    belongs_to :player

    validates_uniqueness_of :school_id, :scope => [:player_id]

Then in my schools_controller I have

schools_controller.rb

def show
  @school = School.find(params[:id], :include => [{:offers => :player}])
  @seniors = @school.teamplayers.sr

My issue is that I need to display a field from the offers model that is associated to the relationship between the School and the Player. Currently I'm performing an additional query in the view to get this field.

schools/show.haml.html

- @srpg.each do |player|
  = Offer.find_by_school_id_and_player_id(@school.id, player.id).status

Obviously this is causing a N+1 issue, but I can't seem to figure out a way to bring back both the offer.status and the player.* in the same record.


Solution

  • Work with the offers instead:

    # in model
    class Offer
      belongs_to :player
      scope :of_seniors, includes(:player).where('player.kind = "senior"')
    end
    
    # in controller
    @seniors_offers = @school.offers.of_seniors
    
    # in view
    - for offer in @seniors_offers
      = offer.player.name
      = offer.status
    - end