Johshi Johshi - 2 months ago 8
Ruby Question

Has_many though -- how to add a model in Rails 4?

Say, I have these models:

class Account < ActiveRecord::Base
has_many :account_games, :dependent => :destroy
has_many :games, :through => :account_games
end

class Game < ActiveRecord::Base
has_many :account_games, :dependent => :destroy
has_many :accounts, :through => :account_games
end

class AccountGame < ActiveRecord::Base
belongs_to :account
belongs_to :game

validates :account, presence: true
validates :game, presence: true
end


I know I could do this in Rails 3:

@account = Account.new(params[:user])
@accountgame = @account.account_games.build(:game => Game.first, :score => 100)
@accountgame.save


Update:

# or
@account = Account.new(params[:user])
@account.games << Game.first
# what's next? any other setting required and if so where?


That is, I already have a game and I want to add it to an account. How can I do this in Rails 4?

Answer

What version of Rails are you on exactly? I'm not able to recreate your problem with a new Rails app under 4.2.5.1.

Migrations:

Account migration:

class CreateAccounts < ActiveRecord::Migration
  def change
    create_table :accounts do |t|
      t.timestamps null: false
    end
 end
end

Game migration:

class CreateGames < ActiveRecord::Migration
  def change
    create_table :games do |t|
      t.timestamps null: false
    end
  end
end

AccountGame migration:

class CreateAccountGames < ActiveRecord::Migration
  def change
    create_table :account_games do |t|
      t.references :account
      t.references :game
      t.integer :score
      t.timestamps null: false
    end
  end
end

Account model (app/models/account.rb):

class Account < ActiveRecord::Base
  has_many :account_games, dependent: :destroy
  has_many :games, through: :account_games
end

Game model (app/models/game.rb):

class Game < ActiveRecord::Base
  has_many :account_games, dependent: :destroy
  has_many :accounts, through: :account_games
end

AccountGame model (app/models/account_game.rb):

class AccountGame < ActiveRecord::Base
  belongs_to :account
  belongs_to :game

  validates :account, presence: true
  validates :game, presence: true
end

Using it:

Loading development environment (Rails 4.2.5.1)
>> g = Game.create
   (0.1ms)  begin transaction
  SQL (1.1ms)  INSERT INTO "games" ("created_at", "updated_at") VALUES (?, ?)  [["created_at", "2016-09-20 03:31:41.484101"], ["updated_at", "2016-09-20 03:31:41.484101"]]
   (1.0ms)  commit transaction
=> #<Game id: 2, created_at: "2016-09-20 03:31:41", updated_at: "2016-09-20 03:31:41">
>> a = Account.new
=> #<Account id: nil, created_at: nil, updated_at: nil>
>> a.account_games.build(game: Game.first, score: 100)
  Game Load (0.2ms)  SELECT  "games".* FROM "games"  ORDER BY "games"."id" ASC LIMIT 1
=> #<AccountGame id: nil, account_id: nil, game_id: 1, score: 100, created_at: nil, updated_at: nil>
>> a.save
   (0.1ms)  begin transaction
  SQL (0.4ms)  INSERT INTO "accounts" ("created_at", "updated_at") VALUES (?, ?)  [["created_at", "2016-09-20 03:32:02.532976"], ["updated_at", "2016-09-20 03:32:02.532976"]]
  SQL (0.2ms)  INSERT INTO "account_games" ("game_id", "score", "account_id", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?)  [["game_id", 1], ["score", 100], ["account_id", 2], ["created_at", "2016-09-20 03:32:02.535031"], ["updated_at", "2016-09-20 03:32:02.535031"]]
   (1.0ms)  commit transaction
=> true
>> a.account_games
  AccountGame Load (0.2ms)  SELECT "account_games".* FROM "account_games" WHERE "account_games"."account_id" = ?  [["account_id", 2]]
=> #<ActiveRecord::Associations::CollectionProxy [#<AccountGame id: 2, account_id: 2, game_id: 1, score: 100, created_at: "2016-09-20 03:32:02", updated_at: "2016-09-20 03:32:02">]>

You can also do:

>> a.account_games.count
  Account Load (0.1ms)  SELECT  "accounts".* FROM "accounts" WHERE "accounts"."id" = ? LIMIT 1  [["id", 2]]
   (0.1ms)  SELECT COUNT(*) FROM "account_games" WHERE "account_games"."account_id" = ?  [["account_id", 2]]
=> 1

>> a.games << Game.first
  Game Load (0.2ms)  SELECT  "games".* FROM "games"  ORDER BY "games"."id" ASC LIMIT 1
   (0.2ms)  begin transaction
   SQL (0.4ms)  INSERT INTO "account_games" ("account_id", "game_id", "created_at", "updated_at") VALUES (?, ?, ?, ?)  [["account_id", 2], ["game_id", 1], ["created_at", "2016-09-20 04:52:07.058592"], ["updated_at", "2016-09-20 04:52:07.058592"]]
   (0.8ms)  commit transaction
  Game Load (0.2ms)  SELECT "games".* FROM "games" INNER JOIN "account_games" ON "games"."id" = "account_games"."game_id" WHERE "account_games"."account_id" = ?  [["account_id", 2]]
=> #<ActiveRecord::Associations::CollectionProxy [#<Game id: 1, created_at: "2016-09-20 03:24:16", updated_at: "2016-09-20 03:24:16">, #    <Game id: 1, created_at: "2016-09-20 03:24:16", updated_at: "2016-09-20 03:24:16">, #<Game id: 1, created_at: "2016-09-20 03:24:16", updated_at: "2016-09-20 03:24:16">]>
>> a.account_games.count
  Account Load (0.1ms)  SELECT  "accounts".* FROM "accounts" WHERE "accounts"."id" = ? LIMIT 1  [["id", 2]]
   (0.1ms)  SELECT COUNT(*) FROM "account_games" WHERE "account_games"."account_id" = ?  [["account_id", 2]]
=> 2

I'm assuming your Game is valid? E.g. Game.first.valid? == true

Comments