-
-
Save JFickel/7201922 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[1] pry(main)> f = FactoryGirl.build(:tournament, :with_teams, teams: 20) | |
(0.3ms) BEGIN | |
User Exists (0.9ms) SELECT 1 AS one FROM "users" WHERE "users"."email" = '[email protected]' LIMIT 1 | |
User Exists (0.5ms) SELECT 1 AS one FROM "users" WHERE "users"."username" = 'example1' LIMIT 1 | |
SQL (4.2ms) INSERT INTO "users" ("created_at", "email", "encrypted_password", "first_name", "last_name", "updated_at", "username") VALUES ($1, $2, $3, $4, $5, $6, $7) RETURNING "id" [["created_at", Mon, 28 Oct 2013 18:06:58 UTC +00:00], ["email", "[email protected]"], ["encrypted_password", "$2a$04$pQOTHk9MXOUE8ayPjkFzmOg/ZW5j0VjyEPmz0PbTgJJc0qGs5A7Ii"], ["first_name", "Maggie"], ["last_name", "Gerlach"], ["updated_at", Mon, 28 Oct 2013 18:06:58 UTC +00:00], ["username", "example1"]] | |
PgSearch::Document Load (0.9ms) SELECT "pg_search_documents".* FROM "pg_search_documents" WHERE "pg_search_documents"."searchable_id" = $1 AND "pg_search_documents"."searchable_type" = $2 ORDER BY "pg_search_documents"."id" ASC LIMIT 1 [["searchable_id", 1], ["searchable_type", "User"]] | |
User Load (0.7ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT 1 [["id", 1]] | |
SQL (0.8ms) INSERT INTO "pg_search_documents" ("content", "created_at", "searchable_id", "searchable_type", "updated_at") VALUES ($1, $2, $3, $4, $5) RETURNING "id" [["content", "example1 Maggie Gerlach"], ["created_at", Mon, 28 Oct 2013 18:06:58 UTC +00:00], ["searchable_id", 1], ["searchable_type", "User"], ["updated_at", Mon, 28 Oct 2013 18:06:58 UTC +00:00]] | |
(0.3ms) COMMIT | |
NoMethodError: undefined method `each' for 20:Fixnum | |
from /usr/local/rvm/rubies/ruby-2.0.0-p0/lib/ruby/gems/2.0.0/gems/activerecord-4.0.0/lib/active_record/associations/collection_association.rb:333:in `replace' |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(0.4ms) BEGIN | |
User Exists (0.9ms) SELECT 1 AS one FROM "users" WHERE "users"."email" = '[email protected]' LIMIT 1 | |
User Exists (0.2ms) SELECT 1 AS one FROM "users" WHERE "users"."username" = 'example1' LIMIT 1 | |
SQL (3.6ms) INSERT INTO "users" ("created_at", "email", "encrypted_password", "first_name", "last_name", "updated_at", "username") VALUES ($1, $2, $3, $4, $5, $6, $7) RETURNING "id" [["created_at", Mon, 28 Oct 2013 18:21:36 UTC +00:00], ["email", "[email protected]"], ["encrypted_password", "$2a$04$EJhRK2MeTRC4.17vikLLGekWU8zsA.aDKMUbC14mJf.UpEzBSkr8i"], ["first_name", "Rodrigo"], ["last_name", "Wintheiser"], ["updated_at", Mon, 28 Oct 2013 18:21:36 UTC +00:00], ["username", "example1"]] | |
PgSearch::Document Load (0.8ms) SELECT "pg_search_documents".* FROM "pg_search_documents" WHERE "pg_search_documents"."searchable_id" = $1 AND "pg_search_documents"."searchable_type" = $2 ORDER BY "pg_search_documents"."id" ASC LIMIT 1 [["searchable_id", 1], ["searchable_type", "User"]] | |
User Load (0.7ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT 1 [["id", 1]] | |
SQL (0.8ms) INSERT INTO "pg_search_documents" ("content", "created_at", "searchable_id", "searchable_type", "updated_at") VALUES ($1, $2, $3, $4, $5) RETURNING "id" [["content", "example1 Rodrigo Wintheiser"], ["created_at", Mon, 28 Oct 2013 18:21:36 UTC +00:00], ["searchable_id", 1], ["searchable_type", "User"], ["updated_at", Mon, 28 Oct 2013 18:21:36 UTC +00:00]] | |
(0.3ms) COMMIT | |
/usr/local/rvm/rubies/ruby-2.0.0-p0/lib/ruby/gems/2.0.0/gems/activerecord-4.0.0/lib/active_record/associations/collection_association.rb:333:in `replace' | |
/usr/local/rvm/rubies/ruby-2.0.0-p0/lib/ruby/gems/2.0.0/gems/activerecord-4.0.0/lib/active_record/associations/collection_association.rb:42:in `writer' | |
/usr/local/rvm/rubies/ruby-2.0.0-p0/lib/ruby/gems/2.0.0/gems/activerecord-4.0.0/lib/active_record/associations/builder/association.rb:78:in `teams=' | |
/usr/local/rvm/rubies/ruby-2.0.0-p0/lib/ruby/gems/2.0.0/gems/factory_girl-4.2.0/lib/factory_girl/attribute_assigner.rb:16:in `block (2 levels) in object' | |
/usr/local/rvm/rubies/ruby-2.0.0-p0/lib/ruby/gems/2.0.0/gems/factory_girl-4.2.0/lib/factory_girl/attribute_assigner.rb:15:in `each' | |
/usr/local/rvm/rubies/ruby-2.0.0-p0/lib/ruby/gems/2.0.0/gems/factory_girl-4.2.0/lib/factory_girl/attribute_assigner.rb:15:in `block in object' | |
/usr/local/rvm/rubies/ruby-2.0.0-p0/lib/ruby/gems/2.0.0/gems/factory_girl-4.2.0/lib/factory_girl/attribute_assigner.rb:14:in `tap' | |
/usr/local/rvm/rubies/ruby-2.0.0-p0/lib/ruby/gems/2.0.0/gems/factory_girl-4.2.0/lib/factory_girl/attribute_assigner.rb:14:in `object' | |
/usr/local/rvm/rubies/ruby-2.0.0-p0/lib/ruby/gems/2.0.0/gems/factory_girl-4.2.0/lib/factory_girl/evaluation.rb:12:in `object' | |
/usr/local/rvm/rubies/ruby-2.0.0-p0/lib/ruby/gems/2.0.0/gems/factory_girl-4.2.0/lib/factory_girl/strategy/build.rb:9:in `result' | |
/usr/local/rvm/rubies/ruby-2.0.0-p0/lib/ruby/gems/2.0.0/gems/factory_girl-4.2.0/lib/factory_girl/factory.rb:42:in `run' | |
/usr/local/rvm/rubies/ruby-2.0.0-p0/lib/ruby/gems/2.0.0/gems/factory_girl-4.2.0/lib/factory_girl/factory_runner.rb:23:in `block in run' | |
/usr/local/rvm/rubies/ruby-2.0.0-p0/lib/ruby/gems/2.0.0/gems/activesupport-4.0.0/lib/active_support/notifications.rb:161:in `instrument' | |
/usr/local/rvm/rubies/ruby-2.0.0-p0/lib/ruby/gems/2.0.0/gems/factory_girl-4.2.0/lib/factory_girl/factory_runner.rb:22:in `run' | |
/usr/local/rvm/rubies/ruby-2.0.0-p0/lib/ruby/gems/2.0.0/gems/factory_girl-4.2.0/lib/factory_girl/strategy_syntax_method_registrar.rb:19:in `block in define_singular_strategy_method' | |
(pry):2:in `__pry__' | |
/usr/local/rvm/rubies/ruby-2.0.0-p0/lib/ruby/gems/2.0.0/gems/pry-0.9.12.2/lib/pry/pry_instance.rb:328:in `eval' | |
/usr/local/rvm/rubies/ruby-2.0.0-p0/lib/ruby/gems/2.0.0/gems/pry-0.9.12.2/lib/pry/pry_instance.rb:328:in `evaluate_ruby' | |
/usr/local/rvm/rubies/ruby-2.0.0-p0/lib/ruby/gems/2.0.0/gems/pry-0.9.12.2/lib/pry/pry_instance.rb:278:in `re' | |
/usr/local/rvm/rubies/ruby-2.0.0-p0/lib/ruby/gems/2.0.0/gems/pry-0.9.12.2/lib/pry/pry_instance.rb:254:in `rep' | |
/usr/local/rvm/rubies/ruby-2.0.0-p0/lib/ruby/gems/2.0.0/gems/pry-0.9.12.2/lib/pry/pry_instance.rb:234:in `block (3 levels) in repl' | |
/usr/local/rvm/rubies/ruby-2.0.0-p0/lib/ruby/gems/2.0.0/gems/pry-0.9.12.2/lib/pry/pry_instance.rb:232:in `loop' | |
/usr/local/rvm/rubies/ruby-2.0.0-p0/lib/ruby/gems/2.0.0/gems/pry-0.9.12.2/lib/pry/pry_instance.rb:232:in `block (2 levels) in repl' | |
/usr/local/rvm/rubies/ruby-2.0.0-p0/lib/ruby/gems/2.0.0/gems/pry-0.9.12.2/lib/pry/pry_instance.rb:231:in `catch' | |
/usr/local/rvm/rubies/ruby-2.0.0-p0/lib/ruby/gems/2.0.0/gems/pry-0.9.12.2/lib/pry/pry_instance.rb:231:in `block in repl' | |
/usr/local/rvm/rubies/ruby-2.0.0-p0/lib/ruby/gems/2.0.0/gems/pry-0.9.12.2/lib/pry/pry_instance.rb:230:in `catch' | |
/usr/local/rvm/rubies/ruby-2.0.0-p0/lib/ruby/gems/2.0.0/gems/pry-0.9.12.2/lib/pry/pry_instance.rb:230:in `repl' | |
/usr/local/rvm/rubies/ruby-2.0.0-p0/lib/ruby/gems/2.0.0/gems/pry-0.9.12.2/lib/pry/pry_class.rb:170:in `start' | |
/usr/local/rvm/rubies/ruby-2.0.0-p0/lib/ruby/gems/2.0.0/gems/railties-4.0.0/lib/rails/commands/console.rb:90:in `start' | |
/usr/local/rvm/rubies/ruby-2.0.0-p0/lib/ruby/gems/2.0.0/gems/railties-4.0.0/lib/rails/commands/console.rb:9:in `start' | |
/usr/local/rvm/rubies/ruby-2.0.0-p0/lib/ruby/gems/2.0.0/gems/railties-4.0.0/lib/rails/commands.rb:64:in `<top (required)>' | |
bin/rails:4:in `require' | |
bin/rails:4:in `<main>' | |
=> nil |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Read about factories at https://github.com/thoughtbot/factory_girl | |
FactoryGirl.define do | |
factory :tournament do | |
sequence(:title) {|n| "Tournament#{n}"} | |
game 'League of Legends' | |
starts_at 1.minute.since | |
association :owner, factory: :user | |
trait :with_teams do | |
mode 'team' | |
after :create do |tournament, evaluator| | |
FactoryGirl.create_list :tournament_membership, evaluator.teams, team: team, tournament: tournament | |
end | |
end | |
trait :with_users do | |
mode 'individual' | |
after :create do |tournament, evaluator| | |
FactoryGirl.create_list :tournament_membership, evaluator.users, user: user, tournament: tournament | |
end | |
end | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
FactoryGirl.define do | |
factory :user do | |
sequence(:username) { |n| "example#{n}"} | |
first_name Faker::Name.first_name | |
last_name Faker::Name.last_name | |
email { "#{username}@example.com" } | |
password "password" | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Team < ActiveRecord::Base | |
has_many :team_memberships | |
has_many :users, through: :team_memberships | |
has_many :events | |
has_many :tournament_memberships | |
has_many :tournaments, through: :tournament_memberships | |
has_many :team_showings | |
has_many :matches, through: :team_showings | |
has_many :affiliated_tournament_relationships, | |
foreign_key: :affiliate_team_id, | |
class_name: 'Affiliation', | |
dependent: :destroy | |
has_many :affiliated_tournaments, | |
through: :affiliated_tournament_relationships, | |
source: :affiliated_tournament, | |
class_name: 'Tournament' | |
has_many :affiliated_group_relationships, | |
foreign_key: :affiliate_team_id, | |
class_name: 'Affiliation', | |
dependent: :destroy | |
has_many :affiliated_groups, | |
through: :affiliated_group_relationships, | |
source: :affiliated_group, | |
class_name: 'Group' | |
has_many :affiliated_team_relationships, | |
foreign_key: :affiliate_team_id, | |
class_name: 'Affiliation', | |
dependent: :destroy | |
has_many :affiliated_teams, | |
through: :affiliated_team_relationships, | |
source: :affiliated_team, | |
class_name: 'Team' | |
has_many :affiliate_team_relationships, | |
foreign_key: :affiliated_team_id, | |
class_name: 'Affiliation', | |
dependent: :destroy | |
has_many :affiliates, | |
through: :affiliate_team_relationships, | |
source: :affiliate_team, | |
class_name: 'Team' | |
belongs_to :leader, foreign_key: 'user_id', class_name: User | |
validates :name, presence: true, length: { minimum: 3, maximum: 24 }, uniqueness: { case_sensitive: false } | |
mount_uploader :avatar, AvatarUploader | |
include PgSearch | |
pg_search_scope :text_search, | |
against: :name, | |
using: { tsearch: { prefix: true }} | |
multisearchable against: :name, | |
using: { tsearch: { prefix: true }} | |
def self.construct(options) | |
team = Team.new(name: options[:name]) | |
team.team_memberships << TeamMembership.new(user_id: options[:leader].id) | |
team.leader = options[:leader] | |
return team | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Tournament < ActiveRecord::Base | |
include ActiveModel::Validations | |
attr_accessor :start_date, :start_hour, :start_minute, :start_period | |
belongs_to :owner, foreign_key: 'user_id', class_name: User | |
has_many :tournament_memberships | |
has_many :users, through: :tournament_memberships | |
has_many :teams, through: :tournament_memberships | |
has_many :matches, inverse_of: :tournament | |
has_many :user_showings, through: :matches | |
has_many :team_showings, through: :matches | |
has_many :moderator_roles | |
has_many :moderators, through: :moderator_roles, source: :user | |
serialize :bracket | |
has_many :affiliate_team_relationships, foreign_key: :affiliated_tournament_id, class_name: 'Affiliation', dependent: :destroy | |
has_many :affiliates, through: :affiliate_team_relationships, source: :affiliate_team, class_name: 'Team' | |
include PgSearch | |
pg_search_scope :text_search, | |
against: {title: 'A', description: 'B'}, | |
using: { tsearch: { prefix: true }} | |
multisearchable against: [:title, :description], | |
using: { tsearch: { prefix: true }} | |
validates :title, presence: true | |
validates :game, presence: true | |
validates_with TimeValidator, on: :create | |
validates_with TimeValidator, on: :update, if: :time_parameters? | |
before_save :set_starts_at, if: :time_parameters? | |
def set_starts_at | |
self.starts_at = Time.zone.parse("#{start_date} #{start_hour}:#{start_minute}#{start_period}") | |
end | |
def time_parameters? | |
start_hour.present? || start_minute.present? || start_date.present? | |
end | |
def start | |
reset_bracket | |
rounds = calculate_rounds | |
self.bracket = [[nil]] | |
rounds.times do |i| | |
self.bracket.unshift(Array.new((2**(i+1))/2)) | |
end | |
initialize_bracket | |
self.started = true | |
self.save | |
end | |
def reset_bracket | |
self.user_showings.each(&:destroy) | |
self.matches.destroy_all | |
self.bracket = nil | |
end | |
def calculate_rounds | |
Math.log2(tournament_memberships.count).ceil | |
end | |
def calculate_filtered_round_size(rounds) | |
2**(rounds - 1) | |
end | |
def calculate_number_of_filter_pairs(filtered_round_size) | |
tournament_memberships.count - filtered_round_size | |
end | |
def add_participant_pair_to_match(match, pair) | |
if self.mode == 'individual' | |
match.user_showings.push UserShowing.new(user_id: pair[0].user_id, top: true), UserShowing.new(user_id: pair[1].user_id) | |
elsif self.mode == 'team' | |
match.team_showings.push TeamShowing.new(team_id: pair[0].team_id, top: true), TeamShowing.new(team_id: pair[1].team_id) | |
end | |
end | |
def add_first_initialized_filtered_round_participant_to_match(match, filter_slots) | |
if self.mode == 'individual' | |
match.user_showings.push UserShowing.new(user_id: tournament_memberships[filter_slots..-1].first.user_id) | |
elsif self.mode == 'team' | |
match.team_showings.push TeamShowing.new(team_id: tournament_memberships[filter_slots..-1].first.team_id) | |
end | |
end | |
def add_filled_matches_to_filter_round(filter_slots) | |
tournament_memberships.first(filter_slots).each_slice(2).with_object([]) do |pair,obj| | |
match = Match.new | |
self.matches << match | |
add_participant_pair_to_match(match, pair) | |
obj << match | |
end | |
end | |
def build_filtered_round_matches_with_odd_remainder(filter_slots) | |
after_filter_round = [] | |
match = Match.new | |
self.matches << match | |
add_first_initialized_filtered_round_participant_to_match(match, filter_slots) | |
after_filter_round << match | |
tournament_memberships[filter_slots+1..-1].each_slice(2) do |pair| | |
match = Match.new | |
self.matches << match | |
add_participant_pair_to_match(match, pair) | |
after_filter_round << match | |
end | |
return after_filter_round | |
end | |
def build_filtered_round_matches_with_even_remainder(filter_slots) | |
tournament_memberships[filter_slots..-1].each_slice(2).with_object([]) do |pair, after_filter_round| | |
match = Match.new | |
self.matches << match | |
add_participant_pair_to_match(match, pair) | |
after_filter_round << match | |
end | |
end | |
def initialize_bracket | |
## Takes the number of rounds and finds how many slots are contested | |
## for the round following the "filter" round. It then takes these contested | |
## slots, multiplies them by two and shoves that amount of players into | |
## the "filter" round. The remainder get moved onto the end of the next round. | |
rounds = calculate_rounds | |
filtered_round_size = calculate_filtered_round_size(rounds) | |
filter_pairs = calculate_number_of_filter_pairs(filtered_round_size) | |
filter_slots = filter_pairs*2 | |
self.bracket[0][0..((filter_slots/2)-1)] = add_filled_matches_to_filter_round(filter_slots) | |
if tournament_memberships[filter_slots..-1].length.odd? | |
self.bracket[1][(filter_pairs/2)..-1] = build_filtered_round_matches_with_odd_remainder(filter_slots) | |
else | |
self.bracket[1][(filter_pairs/2)..-1] = build_filtered_round_matches_with_even_remainder(filter_slots) | |
end | |
end | |
def find_bottom_participant(match) | |
if match.tournament.mode == "individual" | |
match.user_showings.find {|us| us.top == nil } ## methods | |
elsif match.tournament.mode == "team" | |
match.team_showings.find {|ts| ts.top == nil } ## methods | |
end | |
end | |
def find_top_participant(match) | |
if match.tournament.mode == "individual" | |
match.user_showings.find {|us| us.top == true } || match.user_showings.first ## methods | |
elsif match.tournament.mode == "team" | |
match.team_showings.find {|ts| ts.top == true } || match.team_showings.first ## methods | |
end | |
end | |
def create_and_position_new_match(position, new_showing) | |
match = Match.create | |
self.matches << match | |
add_showing_to_match(match, new_showing) | |
self.bracket[position[0]+1][position[1]/2] = match | |
end | |
def add_showing_to_match(match, new_showing) | |
if self.mode == "individual" | |
match.user_showings.push new_showing | |
elsif self.mode == "team" | |
match.team_showings.push new_showing | |
end | |
end | |
def set_new_showing(participant, position) | |
if self.mode == "individual" | |
UserShowing.new(user_id: participant.user_id, top: (position[1].even? ? true : nil) ) | |
elsif self.mode == "team" | |
TeamShowing.new(team_id: participant.team_id, top: (position[1].even? ? true : nil) ) | |
end | |
end | |
def advance position | |
match = self.bracket[position[0]][position[1]] | |
if position[2] == 1 | |
participant = find_bottom_participant(match) | |
else | |
participant = find_top_participant(match) | |
end | |
## Create a new user showing and place him on top if his index is even | |
new_showing = set_new_showing(participant, position) | |
## Place the new user showing the correct position | |
next_match = self.bracket[position[0]+1][position[1]/2] | |
if next_match.nil? | |
create_and_position_new_match(position, new_showing) | |
else | |
add_showing_to_match(next_match, new_showing) | |
end | |
self.save | |
end | |
def delete_slot position | |
match = self.bracket[position[0]][position[1]] | |
if position[2] == 1 | |
showing = find_top_participant(match) | |
else | |
showing = find_top_participant(match) | |
end | |
showing.destroy | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class TournamentMembership < ActiveRecord::Base | |
belongs_to :user | |
belongs_to :tournament | |
belongs_to :team | |
validates :user_id, uniqueness: { scope: :tournament_id, | |
message: 'can only sign up once per tournament'}, if: :individual_mode | |
validates :team_id, uniqueness: { scope: :tournament_id, | |
message: 'can only sign up once per tournament'}, if: :team_mode | |
def individual_mode | |
self.tournament.try(:mode) == 'individual' | |
end | |
def team_mode | |
self.tournament.try(:mode) == 'team' | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment