質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.87%

  • Ruby

    6747questions

    Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

  • HTML5

    3594questions

    HTML5 (Hyper Text Markup Language、バージョン 5)は、マークアップ言語であるHTMLの第5版です。

  • Ruby on Rails 5

    1089questions

データ型の変更の仕方がわからない。

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 300

komorigasa

score 3

前提・実現したいこと

すでに作成してしまったカラムの型を変更したい。

ターミナルにて、
rails g model Listing travel_departure:integer
と実行してしまったのですが、placeの型をinteger→stringに変更したいです。

実際には、
rails g model Listing travel_departure:string
としたかったということです。

実際に行ったこと

rails g migration change_datatype_travel_departure_of_listings
を実行しました。

db/migrate/20180112034439_change_datatype_travel_departure_of_listings.rb
が作成されました。

db/migrate/20180112034439_change_datatype_travel_departure_of_listings.rb

class ChangeDatatypeTravelDepartureOfListings < ActiveRecord::Migration[5.1]
  def change
      change_column :listing, :travel_departure, :string
  end
end



rails db:migrate
実行

エラーコード

== 20180112034439 ChangeDatatypeTravelDepartureOfListings: migrating ==========
-- change_column(:listings, :travel_departure, :string)
rails aborted!
StandardError: An error has occurred, this and all later migrations canceled:

SQLite3::ConstraintException: FOREIGN KEY constraint failed: DROP TABLE "listings"
/Users/hikaru/Desktop/TS/vendor/bundle/gems/sqlite3-1.3.13/lib/sqlite3/statement.rb:108:in `step'

参考にしたサイト通りに行ったのですが、うまくいきません。
参考にしたのは、こちらのURLです。
https://qiita.com/dawn_628/items/13fa64dc6d600e921ce3

ご教授のほど、よろしくお願いいたします。

(追記)db/schema.rb

# This file is auto-generated from the current state of the database. Instead
# of editing this file, please use the migrations feature of Active Record to
# incrementally modify your database, and then regenerate this schema definition.
#
# Note that this schema.rb definition is the authoritative source for your
# database schema. If you need to create the application database on another
# system, you should be using db:schema:load, not running all the migrations
# from scratch. The latter is a flawed and unsustainable approach (the more migrations
# you'll amass, the slower it'll run and the greater likelihood for issues).
#
# It's strongly recommended that you check this file into your version control system.

ActiveRecord::Schema.define(version: 20180109075510) do

  create_table "listings", force: :cascade do |t|
    t.string "travel_type"
    t.string "travel_country"
    t.integer "travel_departure"
    t.integer "travel_arrival"
    t.string "address"
    t.string "listing_title"
    t.text "listing_content"
    t.boolean "active"
    t.integer "user_id"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.integer "price"
    t.float "latitude"
    t.float "longitude"
    t.index ["user_id"], name: "index_listings_on_user_id"
  end

  create_table "photos", force: :cascade do |t|
    t.integer "listing_id"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.string "image_file_name"
    t.string "image_content_type"
    t.integer "image_file_size"
    t.datetime "image_updated_at"
    t.index ["listing_id"], name: "index_photos_on_listing_id"
  end

  create_table "reservations", force: :cascade do |t|
    t.integer "user_id"
    t.integer "listing_id"
    t.integer "number"
    t.datetime "by_time"
    t.integer "price"
    t.integer "total_price"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.integer "commodity_prices"
    t.index ["listing_id"], name: "index_reservations_on_listing_id"
    t.index ["user_id"], name: "index_reservations_on_user_id"
  end

  create_table "users", force: :cascade do |t|
    t.string "email", default: "", null: false
    t.string "encrypted_password", default: "", null: false
    t.string "reset_password_token"
    t.datetime "reset_password_sent_at"
    t.datetime "remember_created_at"
    t.integer "sign_in_count", default: 0, null: false
    t.datetime "current_sign_in_at"
    t.datetime "last_sign_in_at"
    t.string "current_sign_in_ip"
    t.string "last_sign_in_ip"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.string "provider"
    t.string "uid"
    t.string "image"
    t.string "name"
    t.string "phone_number"
    t.string "description"
    t.integer "price"
    t.index ["email"], name: "index_users_on_email", unique: true
    t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
  end

end
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • komorigasa

    2018/01/14 01:37 編集

    #出たエラー文です。 >>> rails db:migrate == 20180112033122 ChangeTravelDepartureOfListngs: migrating =================== -- change_column(:listings, :travel_departure, :string, {:null=>false, :default=>""}) rails aborted! StandardError: An error has occurred, this and all later migrations canceled:

    キャンセル

  • scivola

    2018/01/14 01:40

    ではさっきまでは :listing だったんですか。変だなあ。ご質問のエラーメッセージには change_column(:listings, :travel_departure, :string) とあって,:listings なんですけどね。それはともかく,原因は分かりました。いま良い解決法を考えています。

    キャンセル

  • komorigasa

    2018/01/14 01:57

    そうなんですね。この投稿をする前に色々といじっていたので、そこでスペルを変えてしまったのかもしれません。夜分遅くにすみません!ありがとうございます。

    キャンセル

回答 1

checkベストアンサー

0

英語版 Stack Overflow に似た問題が挙がっていました。
Tried to change the type of a column, but Rails tries to drop the table instead - Stack Overflow

SQLite 特有の問題のようです。

SQLite3 はカラムを変更する機能を持っていない(?)ので,カラムを変更するには,テーブルを作り直してデータをコピーするという手順を踏むようです。マイグレーションで change_column すると,そういうことを自動的にやってくれます。
それはいいのですが,その際 DROP TABLE,つまりテーブルの削除という工程が入るようです。

で,ご質問のデータベースの場合,photos テーブルなどいくつかのテーブルが listings テーブルへの外部キーを持っています。
schema.rb には外部キー制約についてあらわには書かれていませんが,現状の photos などのテーブルには外部キー制約が設定されていると思います。(何らかの SQLite3 クライアントで確認できます)

この場合,photos テーブルの各レコードに入っている listing_id カラムの値は,listings テーブルに実在する id の値でなければなりません。(実は外部キー制約についてよく理解してないのですが,たぶんそういうことだと思います)

すると,photos などのテーブルにすでにレコードが存在する場合,listings テーブルを削除することは外部キー制約を破ることになります。
だからテーブルが削除できず,結果としてカラムの変更もできない,ということになります。

対策ですが,実はうまい方法が見つかりませんでした。

外部キー制約はマイグレーションで remove_foreign_key とか add_foreign_key とすると,あらわに削除したり追加したりできるようなので,いったん制約を外してカラムの型を変更し,再び制約をかければいいかと思ったのですが,できませんでした。
やり方が間違っているのか,SQLite3 の特性なのか,よく調べていません。

次善の策として,マイグレーションを巻き戻し(当然データは消えるので,CSV とかに書き出しておきます),マイグレーションファイルの travel_departure カラムの型を string に変えて再度 rails db:migrate し,そこに保存しておいたデータを読み込む,というようなことでどうでしょうか。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/01/14 09:41

    返信が遅れてすみません。
    問題はSQLiteにあったんですね。
    ご解説いただいた内容はよくわかりました。
    あれから、教えていただいた内容を元に、rollbackを使って、修正を試みようとしたのですが、新たなエラーの連続で結局解決しませんでした。
    おそらく、エラーに取り組むより、やり直したほうが早いと判断し、途中過程で幸いにもコピーをとっていたので、そこから再び構築しようと思います。
    また、今回のことから、mysqlに切り替えようと思いました。
    なんども丁寧にご回答いただき、ありがとうございました。

    キャンセル

  • 2018/01/15 11:27 編集

    (https://qiita.com/reeenapi/items/9fc38c4f2f8186c78288)
    こちらを参考に、無事sqliteからmysqlに移行することができました。
    データの型の変更もこちらですることができました!
    本当にありがとうございました!

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.87%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • Ruby

    6747questions

    Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

  • HTML5

    3594questions

    HTML5 (Hyper Text Markup Language、バージョン 5)は、マークアップ言語であるHTMLの第5版です。

  • Ruby on Rails 5

    1089questions