[Day 11] MVC 架構介紹了MVC 架構
,提到Model是商業邏輯與資料庫溝通的重要部分。今天就從 Model 的產生,介紹到資料庫遷移。
先建立一個Product
Model,每一筆產品資料要有品名title
,價格price
跟介紹description
欄位。在 CLI 下指令:
rails generate model product title price:float description:text
1.上面這行指令是Rails提供的CLI指令,也可以不用這指令,自己新增需要的檔案,內容再一個個自己輸入,會比較慢而且也有打錯的風險。
2.generate
可以用g
代替。
3.如果這行指令執行後又反悔了,把generate
改成d
就可以回到執行前的狀態
4.有發現price
後面帶float
,description
帶了text
,
Output:
invoke active_record
create db/migrate/20190929051903_create_products.rb
create app/models/product.rb
invoke test_unit
create test/models/product_test.rb
create test/fixtures/products.yml
可以看到 Rails 幫我們產生了四個檔案,前兩個是跟資料表active_record
有關,後兩個跟測試test_unit
有關。
來看第一個檔案 db/migrate/20190929051903_create_products.rb
這是個資料庫遷移(Migration)
檔
class CreateProducts < ActiveRecord::Migration[5.2]
def change
create_table :products do |t|
t.string :title
t.float :price
t.text :description
t.timestamps
end
end
end
在ActiveRecord::Migration[5.2]
的change
類別方法內,包了create_table
這個方法。稍後執行遷移(migration)
後,在資料庫建立一張products
資料表。
讓我們來解析 create_table後面的block 內容:
t.string :title
t.float :price
t.text :description
t.timestamps
t
代表欄位,.string
代表資料型態是string
(預設值,最多接受256個文字
)。因為價格可能會有小數點,所以:price
的型態使用浮點數float
而不是整數integer
。商品介紹可能會超過string
准許的256個字,我使用不限長度的text
。最後一個timestamps
方法是Rails幫我產生的,timestamps
方法會產生created_at
跟updated_at
兩個欄位,代表這筆資料建立時間跟最新更新時間。
所有的資料型態ihower大大都幫大家整理好了,
在遷移檔裡,每個欄位除了設定資料屬性,還可以設定諸如預設值
,欄位是准許空值null
之類的參數。列舉如下:
客製化products
資料表,把20190929051903_create_products.rb 的 create_table 的 block 內容改成:
create_table :products do |t|
t.string :title, :limit => 30
t.float :price, :null => false,
t.text :description, :default => "絕贊商品,只此一家"
t.timestamps
end
這樣 migration 檔就準備好了
跑完第一行code:
rails generate model product title price:float description:text
雖然產生了包含xxx_create_products.rb
共四個檔案,但其實資料庫裡還沒有products
資料表,我們還需要執行資料庫遷移 (Migration)
才真正建立資料表。
執行資料庫遷移 (Migration)
:
bin/rake db:migrate
如果建立成功了,打開db/schema.rb
可以看到長得跟剛才修改的migration
檔有點像,剛建立的products
資料表:
ActiveRecord::Schema.define(version: 2019_09_29_051903) do
enable_extension "plpgsql"
create_table "products", force: :cascade do |t|
t.string "title", limit: 30
t.float "price", null: false
t.text "description", default: "絕讚商品,只此一家"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
end
products
出現了(๑•̀ㅂ•́)و✧
一旦執行了rake db:migrate
,再修改migration
檔就沒用了,因為 Migrations 會自動追蹤哪些變更已經執行過了,以執行的就不會再跑一次。
以剛才的 20190929051903_create_products.rb
為例,當我rake db:migrate
之後,再把
t.text "description", default: "絕讚商品,只此一家"
改成
t.text "description", default: "要買要快"
存檔並跑rake db:migrate
打開schema.rb
來看,products
資料表的description
欄位還是:
t.text "description", default: "絕讚商品,只此一家"
那該怎麼辦?
法一
:建立一個新的migration檔# migration後面是要新增的檔名,可以自己取名
rails g migration change_product_destription_default
就產生db/migrate/xxxx_change_product_destription_default.rb
這個 migration檔。不過內容只有:
class ChangeProductDestriptionDefault < ActiveRecord::Migration[5.2]
def change
end
end
到底這個migration 要做什麼,我們要再輸入指令。
change_column_default
方法,來修改欄位預設值class ChangeProductDestriptionDefault < ActiveRecord::Migration[5.2]
def change
change_column_default :products, :description, "要買要快"
end
end
一樣跑rake db:migrate
完成後,打開schema.rb
來看,products
資料表的description
欄位被改成"要買要快"
:
create_table "products", force: :cascade do |t|
t.string "title", limit: 30
t.float "price", null: false
t.text "description", default: "要買要快"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
法二
:把遷移退回 db:migrate前的狀態把遷移退回 db:migrate前的狀態,在CLI下
rake db:rollback
再把20190929051903_create_products.rb
改成
t.text :description, :default => "要買要快"
存檔後執行rake db:migrate
就可以了
database schema 是資料庫綱要,schema.rb
是用來展示目前資料庫的狀態,並且用 create_table、add_index 等方法,來表達資料庫的結構。由於 schema 是獨立於資料庫系統的(database independent),只要是 Active Record 有支援的資料庫系統,它都可以載入。如果應用程式要散佈到多種資料庫系統,這點會非常有用。
先在 CLI 啟動rails console
(Rails 操作台)
rails console
啟動後,來建立第一筆product
資料
Product.create(title: '哀鳳11', price: 29999)
產生了三行code
Product Create (2.2ms) INSERT INTO "products" ("title", "price", "created_at", "updated_at") VALUES ($1, $2, $3, $4) RETURNING "id" [["title", "哀鳳11"], ["price", 29999.0], ["created_at", "2019-09-29 11:24:48.090598"], ["updated_at", "2019-09-29 11:24:48.090598"]]
(0.4ms) COMMIT
#<Product id: 1, title: "哀鳳11", price: 29999.0, description: "絕讚商品,只此一家", created_at: "2019-09-29 11:24:48", updated_at: "2019-09-29 11:24:48">
第一行是SQL
語法,要把資料塞進products
資料表,第二行是執行時間。第三行就是第一筆Product
資料。
如果不使用方便的 RailsORM
語法,要改輸入落落長的第一行SQL
原生語法,想到就累。由此可見 Rails ORM語法威力的生產效率。