2018年2月24日 星期六

builder pattern




http://rockssdlog.blogspot.jp/2012/05/design-pattern-builder-pattern.html

2018年2月22日 星期四

用 foreign_key 確保資料相依正確性 (referential integrity)

Rails 4.2 以後開始支援 database 的 foreign key,很好的文章:

https://robots.thoughtbot.com/referential-integrity-with-foreign-keys


我們會用

```rb
class User < ActiveRecord::Base
  has_many :posts, dependent: :destroy
end

class Post < ActiveRecord::Base
  belongs_to :user
  validates :user, presence: true
end
```


這種做法來確保 post 有 user,看似沒問題但這些 validation 都在 rails 的 application 層級,而 rails 提供了很多方式讓你跳過這些 validations 和 callbacks,所以是不可信任的。ex:


User.delete_all 會跳過 `dependent: :destroy` callback

更別提我們常常連 `dependent: :destroy` callback 都忘記加(oops~)

所以應該讓 database 加上這個限制確保我們不會不小心搞爆這些資料


```rb
def change
  add_foreign_key :posts, :users
end
```

另外也可以讓 database 幫我們做到 `dependent: destroy` 一樣的事情

```rb
add_foreign_key :posts, :users, on_delete: :cascade
```

會產生 SQL (postgres):


```sql
ALTER TABLE `posts`
ADD CONSTRAINT `posts_user_id_fk`
FOREIGN KEY (`user_id`) REFERENCES `users`(id)
ON DELETE CASCADE;
```

Caveats:rails 的 Polymorphic associations 不適用




避免在 migration 裡面用其他 class,最常誤用 model class

為什麼呢?因為 migration 是永久留在那裡的,但是某些 class 是在未來可能被刪掉的,所以一個好的 migration file 要能夠讓 scope 維持在 migration file 裡

> While migrations contain the full history of the database schema for a project, they are always run in the context of the current codebase. Referencing a model constant, while tempting, can lead to issues down the road. - Upcase



Bad example

```rb
class AddAdminFlagToUsers < ActiveRecord::Migration
  def up
    add_column :users, :admin, :boolean, default: false
    User.update_all(admin: false)
    change_column_null :users, :admin, false
  end

  def down
    remove_column :users, :admin
  end
end
```

1. User 可能未來不存在,這樣 migration 會 failed
2. 一個好的 practice 在裡面,migration 要分兩階段,設完 boolean all false 才設 null: false

與其用 class, 直接使用 connection instance 執行 sql 在這裡會是比較好的做法:


```rb

class AddAdminFlagToUsers < ActiveRecord::Migration
  def up
    add_column :users, :admin, :boolean, default: false

    connection.update(<<-SQL)
      UPDATE users SET admin = 'f'
    SQL

    change_column_null :users, :admin, false
  end

  def down
    remove_column :users, :admin
  end
end

```

https://thoughtbot.com/upcase/decks/4/flashcards/23

Test 4 phases


Setup -> Exercise -> Verify -> Teardown


Setup: 準備資料
Exercise: 做事情
Verify: 確認事情正確執行
Teardown: 還原成 setup 前的狀態


好的 test 是依序執行這四個步驟



And also, a good test should avoid mystery guess , 意思就是 test 應該一眼就看懂

https://robots.thoughtbot.com/mystery-guest

像是 rspec 的let 雖然很方便,但很容易讓人在讀單一 test 的時候不知道這些變數是怎麼生成的,before block 也是,所以應該想辦法避免。



https://robots.thoughtbot.com/four-phase-test

2018年2月3日 星期六

rails after_create and after_commit

after_create 有時候觸發的時候 database 還沒寫入,所以要確定 database 寫入以後才執行的話應該放到 after_commit

例如

```ruby
ActiveRecord::Base.transaction do
  order = build_order
  order.save!
  do_something_1
  do_something_2
end
```

上述do_something 1 跟 2 可能花很久時間,但這時 after_create 已經觸發了,這樣就會有可能發生 error,尤其是 after_create 執行的動作需要在 order 已經建立為前提的話。


另外還有一個 activerecord lifecycle 的坑就是當 server restart 時可能會中斷 lifecycle,所以其實這種東西應該要盡可能放到 sidekiq 執行,確保不會漏掉。

2018年2月1日 星期四

rails bigdecimal and postgres scale

從 icoinfo 和 otcbtc 上線以來一直被小數點精度問題搞到,原因是因為直接 `.to_d` 的設定和 rails ActiveRecord 的設定不一樣,導致一堆小 bug

假設我們 postgres decimal 欄位設 scale 為 18,那麼假設我要算 order price:

```rb
price = 2.315.to_d / 1.333
# => 1.736684171042760690172543136

order.price = price
order.save
order.price
# => 1.73668417104276069
```

這就有問題了,假設我有些地方 order 還沒被建立出來,那我要怎麼模擬 scale 只有 18 的狀態?到底第 19 位會怎麼處理? floor? round?


今天受不了了查了一下 soure code:

rails source code:


  • round value /Users/wayne/Codes/rails/activemodel/lib/active_model/type/decimal.rb:63
  • precision settings /Users/wayne/Codes/rails/activemodel/lib/active_model/type/value.rb:9
  • initialize decimal object: /Users/wayne/Codes/rails/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb:515

簡言之,scale 的後一位會被用 `round` 方法四捨五入





chmod 改變檔案權限


Linux檔案的基本權限就有九個,分別是owner/group/others三種身份各有自己的read/write/execute權限, 先複習一下剛剛上面提到的資料:檔案的權限字元為:『-rwxrwxrwx』, 這九個權限是三個三個一組的!其中,我們可以使用數字來代表各個權限,各權限的分數對照表如下:
r:4
w:2
x:1
每種身份(owner/group/others)各自的三個權限(r/w/x)分數是需要累加的,例如當權限為: [-rwxrwx---] 分數則是:
owner = rwx = 4+2+1 = 7
group = rwx = 4+2+1 = 7
others= --- = 0+0+0 = 0

chmod 777 index.js


http://linux.vbird.org/linux_basic/0210filepermission.php

http://www.macinstruct.com/node/415