①テーブルの作成
$ 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.rb
にhas_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 console
でirbを開く
④以下を実行
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,