U-Yuri’s 健忘録

U-Yuri’s 備忘録

プログラミングを勉強しています。アウトプットに活用しているブログです。

【rails】複数の外部キーを設定しrubyでテストする方法

①テーブルの作成

$ rails g model Pokemon sinka:string name:string special:string hp:integer zokusei:string

rails db:migrateでmigrateファイルを作成 ③db/migrate/~_create_pokemons.rbを編集

class CreatePokemons < ActiveRecord::Migration[7.0]
  def change
    create_table :pokemons do |t|
      t.string :sinka
      t.string :name
      t.string :special
      t.integer :hp
      t.string :zokusei
      t.references :tokusei, foreign_key: true
      t.integer :skill1_id, index: true
      t.integer :skill2_id, index: true

      t.timestamps
    end
    add_foreign_key :pokemons, :skills, column: :skill1_id
    add_foreign_key :pokemons, :skills, column: :skill2_id
  end
end

※t.referencesはカラム作成+外部キーを作成するが、カラムの名前を選ぶことができない(つまり複数作成できない)ので、t.integerを使い、add_foreign_keyを設定する必要がある。

add/models/~.rbを編集

class Pokemon < ApplicationRecord
  belongs_to :skill1, class_name: 'Skill', foreign_key: :skill1_id
  belongs_to :skill2, class_name: 'Skill', foreign_key: :skill2_id, optional: true
  belongs_to :tokusei
end

belongs_to :skill1はクラス名ではないので、 class_name: 'Skill'でクラス名を指定してあげる。 ※skill2はnullの可能性もあるので、optional: true でnullでもOKの設定を追記(これを書かないとdb:reset時に以下のようなエラーになる)。
エラー画面

% rails db:reset
Dropped database 'db/development.sqlite3'
Dropped database 'db/test.sqlite3'
Created database 'db/development.sqlite3'
Created database 'db/test.sqlite3'
rails aborted!
ActiveRecord::RecordInvalid: Validation failed: Skill2 must exist
/Users/macuser/PokeCa/Pokeca/db/seeds.rb:96:in `<main>'
Tasks: TOP => db:reset => db:setup => db:seed
(See full trace by running task with --trace)

add/models/skill.rbを編集

class Skill < ApplicationRecord
  has_many :pokemons, foreign_key: :skill1_id
  has_many :pokemons, foreign_key: :skill2_id
end

⑥seeds.rbを編集

Pokemon.create!(
  name: 'ビッパ',
  sinka: 'たね',
  zokusei: '無色',
  hp: '60',
  special: nil,
  tokusei_id: '2',
  skill1_id: '3',
  skill2_id: nil
)

※空白は『''』より『nil』の方が良い。

⑦コードが動くかrails consoleで確認

irb(main):002> p = Pokemon.find_by(name:'ビッパ')
  Pokemon Load (0.2ms)  SELECT "pokemons".* FROM "pokemons" WHERE "pokemons"."name" = ? LIMIT ?  [["name", "ビッパ"], ["LIMIT", 1]]
=> 
#<Pokemon:0x000000010ae44fc0
...
irb(main):003> p.skill1
  Skill Load (0.2ms)  SELECT "skills".* FROM "skills" WHERE "skills"."id" = ? LIMIT ?  [["id", 3], ["LIMIT", 1]]
=> 
#<Skill:0x000000010b20b8e8
 id: 3,
 name: "ひっさつまえば",
 koka: "コインを1回投げウラなら、このワザは失敗。",
 attack_point: 30,
 symbol: "",
 created_at: Fri, 02 Feb 2024 06:27:38.514466000 UTC +00:00,
 updated_at: Fri, 02 Feb 2024 06:27:38.514466000 UTC +00:00>
irb(main):004> 

確認完了。

■has_manyの設定(記載し忘れていたので追記) app/models/skill.rbhas_manyを設定

class Skill < ApplicationRecord
  has_many :pokemons1, class_name: 'Pokemon', foreign_key: :skill1_id
  has_many :pokemons2, class_name: 'Pokemon', foreign_key: :skill2_id
end

※複数でない場合は'foreign_key:'のデフォルトで良いので設定は必要なく'has_many :pokemons'だけでいい。 今回は複数なのでhas_many :pokemons1と設定しclass_name: 'Pokemon'で指定する必要がある。

■テストする方法 ①$ rails db:reset実行 ②$ rails consoleirbを開く ④以下を実行

irb(main):009> p = Deck.find_by(name:'ゲンガーデッキ')
  Deck Load (0.2ms)  SELECT "decks".* FROM "decks" WHERE "decks"."name" = ? LIMIT ?  [["name", "ゲンガーデッキ"], ["LIMIT", 1]]
=> 
#<Deck:0x00000001124e28d0
...
irb(main):010> p.card_in_decks
  CardInDeck Load (2.7ms)  SELECT "card_in_decks".* FROM "card_in_decks" WHERE "card_in_decks"."deck_id" = ?  [["deck_id", 1]]
=> 
[#<CardInDeck:0x0000000111b95d90
  id: 1,
  deck_id: 1,
  pokemon_id: 1,
  item_id: nil,
  support_id: nil,
  pokemon_no_item_id: nil,
  stajiamu_id: nil,
  energy_id: nil,
  created_at: Sat, 03 Feb 2024 05:13:25.184044000 UTC +00:00,
  updated_at: Sat, 03 Feb 2024 05:13:25.184044000 UTC +00:00>,
 #<CardInDeck:0x0000000111c37a28
  id: 2,
  deck_id: 1,
  pokemon_id: nil,
  item_id: 2,
  support_id: nil,
  pokemon_no_item_id: nil,
  stajiamu_id: nil,
  energy_id: nil,
  created_at: Sat, 03 Feb 2024 05:13:25.193452000 UTC +00:00,
  updated_at: Sat, 03 Feb 2024 05:13:25.193452000 UTC +00:00>,
 #<CardInDeck:0x0000000111c37910
  id: 3,
  deck_id: 1,
  pokemon_id: nil,
  item_id: nil,
  support_id: 1,
  pokemon_no_item_id: nil,
  stajiamu_id: nil,
  energy_id: nil,