Jex’s Note

Rails DB & Migration

(最後更新: 2016-05-01)

連接 sqlite3 設定

rails 預設連接的 DB,開發階段才使用

config/database.yml

development:
  <<: *default
  database: db/development.sqlite3

有個小缺點,即使欄位有限制字數,但 sqlite 仍然可以超出字數且 insert 成功

連接 MySQL 設定

  • ubuntu 可能要再安裝sudo apt-get install libmysqlclient-dev
  • 安裝 MySQL 可參考這

1) 設定好 config/database.yml

production:
  adapter: mysql2
  encoding: utf8
  database: myapp_production
  username: root
  password:
  host: 127.0.0.1
  port: 3306
  strict: false                     # 關閉此模式, 否則存超過 size 的資料會噴 error, 讓它自動截斷

2) Gemfile

gem 'mysql2', '~> 0.4.3'
  • ubuntu 需要再安裝 libmysqlclient-dev, 否則 bundle 安裝到 mysql2 時會噴錯
  • 要強制指定版號, 不然會噴 error : Specified 'mysql2' for database adapter, but the gem is not loaded. Addgem ‘mysql2’to your Gemfile (and ensure its version is at the minimum required by ActiveRecord). (Gem::LoadError)

3) 建立資料庫

RAILS_ENV=production rake db:create

4) 執行 migrate

rake db:migrate

沒有的話, 建立 table : rails g migration create_videos

註) 連到 MySQL console

rails dbconsole

連接 PostgreSQL 設定

安裝 PostgreSQL 可參考這

1) 設定好 config/database.yml

default: &default
  adapter: postgresql
  pool: 5
  timeout: 5000

development:
  <<: *default
  adapter: postgresql
  encoding: unicode
  database: myapp_development

2) Gemfile

gem 'pg'

3) 建立資料庫 (使用 Postgres 或 rails 的 command 都可以)

createdb myapp_development
或
rake db:create

4) 執行 migrate

rake db:migrate

註) 連到 MySQL console

rails dbconsole

Command

rake db:create                                  # 建立目前 RAILS_ENV 環境的資料庫
rake db:create:all                              # 建立所有環境的資料庫
rake db:drop                                    # 刪除目前 RAILS_ENV 環境的資料庫
rake db:drop:all                                # 刪除所有環境的資料庫
rake db:migrate                                 # 執行 migration
rake db:migrate RAILS_ENV=development           # 指定 development 環境執行 migration
rake db:migrate:up VERSION=20150713155732       # 執行特定版本的 migration
rake db:migrate:down VERSION=20150713155732     # 回復特定版本的 migration
rake db:rollback                                # To rollback the previous migration
rake db:rollback STEP=3                         # 回復前 3 個 migration
rake db:version                                 # 顯示 Current version: 20150713155732
rake db:seed                                    # 執行 db/seeds.rb (種子資料)
rake db:schema:dump                             # Dump the current db state. 產生 db/schema.rb
rake db:setup                                   # Creates the db, loads schema, & seed.    ( When you start working on an existing app
  • 不加上 RAILS_ENV 預設就是 development
  • rails 的 db 可以分為 production 跟 development, 所以可以用 RAILS_ENV 指定哪個 DB

欄位

欄位型態

  • :string : 有限的字串長度, 如果不指定長度, 預設是 varchar(255)
  • :text : 不限的字串長度
  • :integer : 整數
  • :float : 浮點數
  • :decimal : 十進位數
  • :datetime : 日期時間
  • :timestamp : 時間戳章, 型態為 datetime
  • :date : 日期
  • :time : 時間
  • :binary : 二進位, blob
  • :boolean : 布林值
  • :references : 用來參照到其他 Table 的外部鍵, 型態為 integer

tinyint 與 boolean

1) MySQL 有 tinyint 欄位, 但 Rails 不支援, 但使用 integer + limit 來取代, 如下

t.integer :status, :limit => 2

2) MySQL 沒有 boolean 的型態, Rails 是用 tinyint(1) 來支援 MySQL 的 boolean

integer 補充

如果沒有指定 limit 的話, 預設會建立 int(11), 但如果需要建立 BIGINT,

又該指定多少的 limit 呢? 參考以下對照表

 :limit     Numeric Type    Column Size     Max Value
-----------------------------------------------------------------------
    1       TINYINT         1 byte          127
    2       SMALLINT        2 bytes         32767
    3       MEDIUMINT       3 bytes         8388607
    4       INT(11)         4 bytes         2147483647
    8       BIGINT          8 bytes         9223372036854775807

預設 INT(11) = limit 4

add_column :users, :money, :integer

BIGINT = limit 5~8

add_column :users, :money, :integer, limit: 8

Migrate

產生 migration 指令及命名慣例

rails g migration create_users                      # 建立 TABLE
rails g migration add_confirmable_to_devise         # 新增欄位
rails g migration change_comment_field_name         # 修改欄位

語法

migrate 的方式

def up          # migrate 執行的
def down        # rollback 執行的
def change      # migrate 執行的, 要嘛就 up + down, 不想那麼麻煩就選擇 change

Create Table & 欄位

create_table(:users) do |t|

    t.column :id, 'INT UNSIGNED NOT NULL AUTO_INCREMENT, PRIMARY KEY (id)'
    t.string :id, primary_key: true     # create_table :users, id: false
    t.string :video_id, :limit => 50, :null => false               # primary key 但要自己產生
    t.integer :kind , :limit => 1 , :default => 0 , :null => false , :unsigned => true
    t.boolean  :is_hidden, :default => false   ,:null => false
    t.datetime "delete_at"
    t.string   "title" limit: 100,  default: 0, null: false           (VARCHAR)
    t.text     "body"                                               (TINYTEXT, TEXT, MEDIUMTEXT, or LONGTEXT2)
    t.timestamps                                                    (same as : t.datetime :created_at, :updated_at)
    t.references :article, index: true

end

操作欄位

  • 改default : change_column_default :users, :is_admin, default: true
  • 建立table : create_table :videos do |t|
  • 刪除table : drop_table :people
  • 變更欄位 : change_column :table_name, :field_name, :integer, :limit => 8, :unsigned => true, :null => false, :auto_increment => true
  • 增加欄位 : add_column :table_name, :balance, :integer, default: 0, null: false, unsigned: true
  • 刪除欄位 : remove_column :table_name, :created_at
  • rename欄位 : rename_column :table_name, :id, :udid
  • 增加索引 : add_index :table_name, :email, unique: true
  • 增加組合索引 : add_index :user_views, [:user_id, :article_id]
  • 執行SQL : execute "ALTER TABLE users modify COLUMN id int(8) AUTO_INCREMENT"

Example

change_column :videos, :source_website, :string, :limit => 50, :null => false
add_column :videos, :file_name, :string, :limit => 100, :null => false
add_index :videos, :file_name, :unique => true
add_index :videos, :source_website
add_index "users", ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true
add_index "users_roles", ["user_id", "role_id"], name: "index_users_roles_on_user_id_and_role_id"

欄位參數

  • default: 'Hello'
  • limit: 30
  • null: false
  • first: true # position
  • after: :email # position

unsigned: true

當做 migration 時,這個屬性 rails 本身是不支援的,雖然執行 migrate 不會噴錯誤,但是你可以去 db/schema.rb 看,unsigned: true 是沒有被寫進去的

Comments