dimanche 3 avril 2016

How do I write an SQL query for a has_many through relationship where a foreign_key_id is "1" or NULL in Rails?

I have project where you own a fantasy team (Roster model) and you pick teams (SportsTeam model), similar to a college basketball pool. These two models are joined by a "has many through" relationship on a RosterSpots model. I have different leagues (FantasyLeague model) identified on my Roster model by fantasy_league_id.

I'm trying to set up a view that takes parameter[:fantasy_league_id]. The view will show all of the sports_teams (whether they are owned in that fantasy_league or not) and which sports_teams are currently on a roster in that fantasy_league.

My current code will show all of the teams owned in a fantasy_league, i.e. fantasy_league_id = 1, and all sports_teams where fantasy_league_id is NULL, but I can't figure out how to show a team that is not owned in fantasy_league_id = 1 but is owned in fantasy_league_id = 2. I need another OR but I can't figure out how to write it.

Here is short example:

team      (fantasy_league_id):
Seattle   (NULL),
Atlanta   (1),
Atlanta   (2),
Arizona   (1),
New York  (2)

With params[:fantasy_league_id] = 1, I correctly show Seattle, Atlanta, and Arizona but I need to show New York as not being on a roster in that league.

Here are my models:

class SportsTeam < ActiveRecord::Base
  has_many :roster_spots
  has_many :rosters, through: :roster_spots
  belongs_to :sports_league

  scope :left_joins_rosters, -> { joins("LEFT OUTER JOIN roster_spots 
          ON roster_spots.sports_team_id = sports_teams.id
        LEFT OUTER JOIN rosters ON rosters.id = roster_spots.roster_id" ) }

  scope :select_rosters, -> { select("sports_teams.*, rosters.*") }

  scope :joins_sports_league, -> { joins(:sports_league)
          .select("sports_teams.*, sports_leagues.*") }    

class RosterSpot < ActiveRecord::Base
  belongs_to :sports_team
  belongs_to :roster

class Roster < ActiveRecord::Base
  has_many :roster_spots, dependent: :destroy
  has_many :sports_teams, through: :roster_spots
  belongs_to :fantasy_league

class FantasyLeague < ActiveRecord::Base
  has_many :rosters
  has_many :sports_teams, through: :rosters

Here is my controller:

class StandingsController < ApplicationController
  def list_teams
    @sports_teams = SportsTeam.left_joins_rosters.joins_sports_league
      .select_rosters
      .where("fantasy_league_id is NULL OR fantasy_league_id = ?",      
        params_fantasy_league)
  end

  private

    def params_fantasy_league
      params_fantasy_league = params[:fantasy_league_id] || 1
    end
end

I tried writing the WHERE statement directly in the left_joins_rosters scope but got the same result.

  scope :left_joins_rosters_league, -> { joins("LEFT OUTER JOIN roster_spots 
          ON roster_spots.sports_team_id = sports_teams.id
        LEFT OUTER JOIN rosters ON rosters.id = roster_spots.roster_id
        WHERE fantasy_league_id is NULL OR fantasy_league_id = 1") }

I also considered starting with the FantasyLeague model with a .where(fantasy_league_id: params[:fantasy_league_id], but I think I would need to use a RIGHT OUTER JOIN to get all of the sports teams which isn't supported in SQLite.

Thanks! Axel

Aucun commentaire:

Enregistrer un commentaire