Ruby on Rails long string id

之前有講到使用 UUID 當作 primary key 的方法,因為 postgresql 有提供 uuid,可以直接拿來使用。

接下來的這個方法適用於所有的資料庫,在物件儲存之前先給定它的 id,如此一來就能定義我們所想要的內容了。

先隨便用鷹架產生點東西:

1
rails g scaffold book title

加上 id: :string 讓 id 的型態為 string。

1
2
3
4
5
6
7
8
9
# db/migrate/20170218105724_create_books.rb
class CreateBooks < ActiveRecord::Migration[5.0]
def change
create_table :books, id: :string do |t|
t.string :title
t.timestamps
end
end
end

閱讀全文

Ruby on Rails 5 dynamic subdomains

一個使用者有名字 name 還有自己網頁的子網域 subdomain,我們想要的結果是讓每一位使用者有自己的子網域,而且還可以隨時更改。

假設現在有個使用者是 User.create(name: "akii", subdomain: "akiicat"),在 rails 預設 show 頁面會是 http://localhost:3000/users/1,但我們想把網址變成個人的子網域 http://akiicat.localhost:3000

接下來會用鷹架建立使用者來做示範:

1
2
rails g scaffold user name subdomain
rake db:migrate

修改 routes.rb,加上首頁,然後把 show 的頁面加上 subdomains 的限制。

1
2
3
4
5
6
7
8
# config/routes.rb
Rails.application.routes.draw do
resources :users
constraints subdomains: /.+/ do
get '', to: 'users#show'
end
root to: 'users#index'
end

閱讀全文

Ruby on Rails 5 api subdomain

為了要 demo api subdomain 的頁面是否能夠運作,這邊用鷹架隨便建立個東西。

1
2
rails g scaffold api::v1::books title
rake db:migrate

使用 constraints 限制 subdomain: 'api'

然後用 scope module: 'api' 加上 app/controllers/api 這個資料夾。

1
2
3
4
5
6
7
8
9
10
# config/routes.rb
Rails.application.routes.draw do
constraints subdomain: 'api' do
scope module: 'api' do
namespace :v1 do
resources :books
end
end
end
end

閱讀全文

Ruby on Rails callback 筆記

可用的 callback

以下是 Active Record 可用的 callback,依照執行順序排序:

新建物件

1
2
3
4
5
6
7
8
9
before_validation
after_validation
before_save
around_save
before_create
around_create
after_create
after_save
after_commit/after_rollback

更新物件

1
2
3
4
5
6
7
8
9
before_validation
after_validation
before_save
around_save
before_update
around_update
after_update
after_save
after_commit/after_rollback

閱讀全文

Ruby on Rails foreign key must exist 的問題

rails 在這次的更動之後,如果 belongs_to 的 foreign key 不存在的時,會產生驗證錯誤。

1
2
3
4
5
6
7
8
9
class Author < ActiveRecord::Base
end

class Book < ActiveRecord::Base
belongs_to :author
end

book = Book.create(title: "book")
book.errors.full_messages # => ["Author must exist"]

上面的例子可以看到,我們沒辦法建立 Book 的紀錄。

options

  • required: 如果設為 true 的話,會驗證關聯是否存在。在 rails 5 預設為 true
  • optional: 如果設為 true 的話,不會驗證關聯是否存在。

上面兩個選項都是驗證關聯本身,不是驗證 foreign key 的 id。

閱讀全文

Ruby on Rails 探索 inverse_of

inverse_of

主要功能會去通知對方自己的狀態,可以解決物件不同步的問題。

在 belongs_to 裡的 :inverse_of 會去找尋所對應的 has_one has_many 上相同的名稱,來通知他們之間的關係。

在 has_one has_many 裡的 :inverse_of 會去找尋所對應的 belongs_to 上相同的名稱,來通知他們之間的關係。

如果沒有寫 :inverse_of 這參數,rails 會使用 heuristic algorithm 去猜測名稱,但在如果不是使用標準名稱的話會失效。

Without inverse_of

沒有 :inverse_of 會發生物件不同步的問題,可以看以下的範例:

1
2
3
4
5
6
7
class Author < ActiveRecord::Base
has_many :books
end

class Book < ActiveRecord::Base
belongs_to :author, inverse_of: false
end

閱讀全文

Css 網頁符合瀏覽器大小

vmin
vmin
vmax
vmax

Viewport Percentage Lengths

Viewport Percentage Lengths 有四個不同的單位,分別如下:

  • vh (viewport height): 瀏覽器高度百分比。
  • vw (viewport width): 瀏覽器寬度百分比。
  • vmin (viewport minimum length): vh 與 vw 中較小的值。
  • vmax (viewport maximum length): vh 與 vw 中較大的值。

如果想要讓某個元素佔滿整個瀏覽器,就只要像下面這樣寫,很簡單的:

1
2
3
4
div {
width: 100vw;
height: 100vh;
}

閱讀全文

Ruby on Rails Multiple Foreign Keys

這篇主要是在講說,在一個 Table 裡面有多個 Foreign Keys 會指向同一個 table。例子如下,一首歌 Song 會有歌手 (singer_id) 跟作曲者 (composer_id),都會指向同一個 Singer 的 table。

1
2
3
4
5
6
7
8
┌──────────────────┐                ┌─────────────────────┐
│ Singer │ │ Song │
├──────────────────┤ ├─────────────────────┤
│ id:integer │←───────┐ │ id:integer │
│ name:string │ ├───────│ singer_id:integer │
│ │ └───────│ composer_id:integer │
│ │ │ title:string │
└──────────────────┘ └─────────────────────┘

閱讀全文

Ruby 直接儲存 Tempfile 的方法

先建立一個 Tempfile,然後隨便輸入一些資料進去。

1
2
3
4
5
require 'tempfile'

f = Tempfile.new ''
f.puts("akii")
f.close

Tempfile 在程式結束的時候會 f.unlink 刪除檔案,所以在結束之前可以使用 File.rename 移動檔案,讓檔案逃脫免於被刪除的命運。

1
2
# File.rename("afile", "afile.bak")
File.rename(f, "cat.txt")

閱讀全文

Ruby on Rails Eager Loading 加速:一次拿取所以資料

這個在 rails 裡面,資料有關聯的時候,會產生的一些效能上的問題,假設我們的例子如下:

1
2
3
4
5
6
7
┌──────────────────┐                ┌───────────────────┐
│ Author │ │ Book │
├──────────────────┤ ├───────────────────┤
│ id:integer │←───────┐ │ id:integer │
│ name:string │ └───────│ author_id:integer │
│ │ │ title:string │
└──────────────────┘ └───────────────────┘

當我們在 books controllers 拿了一群東西,像是有 all 或是 where

1
2
@books = Book.all
@books = Book.where(author: @author)

常常接著又在 view 裡面使用 each 抓取了關聯的東西 author,這時 @books 不知道 author 的內容所以又必須呼叫一次 SQL 指令去拿資料,所以當資料量一大的時候,會產生效能上的問題。

1
2
3
@books.each do |book|
book.author
end

閱讀全文