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

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

新規登録して質問してみよう
ただいま回答率
85.48%
Ruby on Rails 5

Ruby on Rails 5は、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

Ruby

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

HTML5

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

Q&A

解決済

1回答

899閲覧

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

komorigasa

総合スコア9

Ruby on Rails 5

Ruby on Rails 5は、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

Ruby

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

HTML5

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

0グッド

2クリップ

投稿2018/01/12 04:34

編集2018/01/13 15:04

###前提・実現したいこと
すでに作成してしまったカラムの型を変更したい。

ターミナルにて、
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

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

scivola

2018/01/13 14:49 編集

change_column の第一引数(テーブル名)が :listings でなく :listing と単数形なのがおかしいですが,それが原因でもなさそうな。エラーメッセージに「外部キー制約が云々」とありますが,travel_departure は外部キーですか。また,db/schema.rb が追記できますか。
komorigasa

2018/01/13 15:07 編集

以前はありがとうございました。 ベストアンサーを押してしまい、迷ったのですが、再度投稿しました。 travel_departure は、外部キーです。 db/schema.rb を追記しました。 よろしくお願いいたします。 :listing、確認してみます!
scivola

2018/01/13 15:32

手元で現象が再現しました。ただし,マイグレーションファイルの change_column の第一引数の :listing は本当は :listings と複数形ではありませんか。確認のうえ,そうであれば訂正してください。エラーの原因は調査中です。
komorigasa

2018/01/13 16:33 編集

ありがとうございます。:listings にして確認したところ、同じようにエラーが出ました。お手数おかけしますが、よろしくお願いします。
komorigasa

2018/01/13 16: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/13 16:40

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

2018/01/13 16:57

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

回答1

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/13 17:18

scivola

総合スコア2108

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

komorigasa

2018/01/14 00:41

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問