週一,要裝得認真點~
基本上開發伴隨著Git版控已經是常見的事,但Git控制著的是Project的版本,對於資料庫不會操作到。
如果我們建立了Migrate檔案並執行後,
$ rails db:migrate
Rails會將裡面內容輸入對應資料庫並記錄,即使手動刪除或使用
$ rails db:rollback
$ rails db:rollback SETP=? ?號代表回覆幾步。
等指令倒退後再刪除,DB內已經建立欄位,要再次輸入同名欄位或table就會有被阻止的況狀。
因此開發中更改table時,需要有正確的流程,避免table無法順利更新等狀況。
正確使用Migrate很繁瑣,但是很安全。
英文不好的我,覺得這兩個語法很重要,製作Model,Controller可以少一點時間查字典。
#irb
2.7.3 :002 > require 'active_support/inflector'
2.7.3 :005 > puts "player".pluralize
players
=> nil
2.7.3 :006 > puts "players".singularize
player
首先打開專案,進到DB資料夾。
我們會說到的部分以開發工具會看到的部分做說明。
我們先建立一個model,請注意我故意Model名輸入複數。
$ rails g model players name age:integer homeland
Running via Spring preloader in process 15399
[WARNING] The model name 'players' was recognized as a plural, using the singular 'player' instead. Override with --force-plural or setup custom inflection rules for this noun before running the generator.
invoke active_record
create db/migrate/20210817060308_create_players.rb
create app/models/player.rb
invoke test_unit
create test/models/player_test.rb
create test/fixtures/players.yml
我們先看。
[WARNING] The model name 'players' was recognized as a plural, using the singular 'player' instead. Override with --force-plural or setup custom inflection rules for this noun before running the generator.
雖然框架已經進化到會幫你改單數,但還是請依照單複數正確操作,避免意外,一樣test部分我們先略。
看看今天的主角群之一20210817060308_create_players.rb這檔案。
class CreatePlayers < ActiveRecord::Migration[6.1]
def change
create_table :players do |t|
t.string :name
t.integer :age
t.string :homeland
t.timestamps
end
end
end
養成習慣執行migrate前,檢查檔案內容。
可以發現name,homeland我沒有輸入string,代表指令可省略string這個與設值,還有沒有其他可省略我不會去記,我只會記如果檢查有問題,直接這個檔案做修改就可以。
為了操作,我們先將age的與設值也改一下。
t.string :age
存擋後執行
$ rails db:migrate
== 20210817060308 CreatePlayers: migrating ====================================
-- create_table(:players)
-> 0.0015s
== 20210817060308 CreatePlayers: migrated (0.0016s) ===========================
可以看到schema.rb長出資料了。
create_table "players", force: :cascade do |t|
t.string "name"
t.string "age"
t.string "homeland"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
end
# create_table,新建table
這代表資料庫(模式)已經建立,請記得一件事,不要手動裡面任何一個字,由Migration來幫你處理。
不要手動修改schema.rb的資料。
我後悔了age我還是想用integer型態紀錄。
建立migration,以下兩個指令請都依序輸入。
$ rails g migration player
$ rails g migration player_change_age_integer
新的migrate檔案依序長得如下
class Player < ActiveRecord::Migration[6.1]
def change
end
end
class PlayerChangeAgeInteger < ActiveRecord::Migration[6.1]
def change
end
end
不一樣的地方只有class名,這也代表migration後面的成為class名,類別無法重複,所以當建立migrate檔案時,migration後面請好好確定,不然也會遇到卡住的狀況。
自己選一個刪掉吧,也只有這時能手動刪migrate檔案。(未執行rails db:migrate前)
class PlayerChangeAgeInteger < ActiveRecord::Migration[6.1]
def change
change_column :players, :age, :integer
end
end
#改變欄位 :哪張資料表, :哪一欄名, :改變內容(這次是型態)
執行
$ rails db:migrate
回到schema.rb。可以發現age欄位的改變。
create_table "players", force: :cascade do |t|
t.string "name"
t.integer "age"
t.string "homeland"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
end
$ ails g migration players_name_to_nickname
class PlayersNameToNickname < ActiveRecord::Migration[6.1]
def change
end
end
class PlayersNameToNickname < ActiveRecord::Migration[6.1]
def change
rename_column :players, :name, :nickname
end
end
# 單一欄位改名 :table_name, old_name, new_name
如果無誤,schema.rb如下
create_table "players", force: :cascade do |t|
t.string "nickname"
t.integer "age"
t.string "homeland"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
end
如果一次想三個都改。
$ rails g migration players_three_columns
#格式如下
def change
change_table :table_name do |t|
t.rename :old_column1, :new_column1
t.rename :old_column2, :new_column2
...
end
end
#示範
def change
change_table :players do |t|
t.rename :nickname, :name
t.rename :age, :power
t.rename :homeland, :country
end
end
如無誤,schema.rb應該如下
create_table "players", force: :cascade do |t|
t.string "name"
t.integer "power"
t.string "country"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
end
$ rails g migration player_add_column_level
#格式
class PlayerAddColumnLevel < ActiveRecord::Migration[6.1]
def change
add_column :table_name, :new_column, :type, :options
end
end
#option部分可以想成額外帶入一些設定,例如是否為唯一(uniq),可否空白,預設值,此部分操作與設值。
#option可以不只一個。
#本次操作
def change
add_column :players, :level, :integer, :default => 1
end
如正確schema.rb如下
create_table "players", force: :cascade do |t|
t.string "name"
t.integer "power"
t.string "country"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.integer "level", default: 1
end
#這邊也應該發現,在schema中,一直都是create_table。
$ rails g migration players_level_default
class PlayersLevelDefault < ActiveRecord::Migration[6.1]
def change
change_column_default :players, :level, 2
end
end
#change_column_default :table_name, :column_name, default_value
#當然預設條件不只一種,會有其他變化。
#schema.rb
create_table "players", force: :cascade do |t|
t.string "name"
t.integer "power"
t.string "country"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.integer "level", default: 2
end
操作與add_column,不操作了。
remove_column :table_name, :column_name
drop_table :table_name
rename_table :table_name, :old_name, :new_name
資料表刪除與改名,如果共同開發,不大可能是輕易決定。操作方式大同小異。
新手初期應該是在修改預設值,uniq等部分會先卡住一下下。
新增資料表create_table
移除資料表drop_table
修改資料表名稱rename_table
修改資料表欄位change_table
新增一個欄位add_column
修改欄位名稱rename_column
修改欄位的型態(type)change_column
移除欄位remove_column
change_column_default
當然有更多的指令,要熟練當然只能查手冊與多練習,反正rails new很便宜....
Active Record Migrations
另外如果自己查資料,看到self.up或down等語法,那屬於舊版本操作,以目前開發,會少用到。
老婆: 老公,你覺得家花香還是野花香?
老公: 當然是家花!
老婆: 你一定嘗過野花,才知道家花香!好,我笑點低