---
title: 20200807 AstroCamp rails 一起做 ptt !
tags: Astro Camp, rails
---
# 20200807 AstroCamp rails 一起做 ptt!
## 分析可能需要的功能
1.
看板需要的東西
Board
title:string
intro:text
deleted_at:datetime, 預設值:nil/null, 下索引(用硬碟空間換取搜尋時間)
(較常被查詢的才要下索引值)
state:[default:noraml,disable,hidden]
Model 是大寫單數
tables 是小寫複數
controller 通常是複數
---
## 碰到的問題
### 為何同一controller裡有相同@實體變數?
![](https://i.imgur.com/H3b2O2O.png)
行為:當創建看板時,將new.html裡的form打包成params,POST到create(action)的裡
因為HTTP本身沒有狀態,雖然在new方法裡有將@board,指定為Board.new,但是在網址切換時,此@board狀態並不會被儲存。
但因為有將params POST到creat,所以可以在下一個creat方法裡再將@board指定為Board.new(params[:board])
(所以其實可以把兩個變數設為不同的名字...但後續製作上會有問題)
### 無窮迴圈
```
class Board < ApplicationRecord
def self.all
where(deleted_at: nil)
end
```
可能where方法也有呼叫all,導致無窮迴圈。
---
要複習的觀念
1. 實體方法,類別方法的差異?
1. 使用的地方?
2. **寫法?**
2. proc是把block物件化,後面可以接block
## 選取資料
Scope(定義選取資料時的範圍) 已經被做好了!
```
module ActiveRecord
class Base
def self.scope(scope_name,callback)
end
end
end
class Book <ActiveRecord::Base
scope :available, -> {where(delete_at: nil)}
end
```
scope 讓一開始在抓資料的時候就不要抓到已被軟刪除的資料
scope可以連段
```
scope :not_hidden, -> {where(stauts: off_line)}
scope :not_deleted, -> {where(deleted_at: nil)}
```
上面可以找出未被刪除且上線狀態不是隱藏的看板!
default_scope所有在找資料的時候都先執行設定的條件
```
default_scope {where(deleted_at: nil)}
scope :available, -> {where(deleted_at: nil)}
```
相當於下面這一塊
```
def self.available
where(deleted_at: nil)
end
```
想取消要手動 => unscope
super 會呼叫上層同名的方法
```
def hello
puts a
end
def hello
super
puts b
end
```
印出a,b
安裝了[paranoia](https://rubygems.org/gems/paranoia)套件,所以上面都不用做了 = =""[github](https://github.com/rubysherpas/paranoia/)
belongs_to ->
has_many 做出(並不是真的把board跟post的model做關聯,只是做出了一些方法,讓你可以找出一些上層的東西)
1. .posts 方法 會去抓某看板的所有文章(會去抓board_id)
翻譯:`select * from posts where board_id=XXX`
如果剛開始建立的欄位不是`board_id`,而是`b_id`,要自己手動加上`foreign_key`
```
has_many :posts, foreign_key: b_id
```
建立文章(從看板的角度)
```
bb = Board.find(9)
bb.posts.create(title: "aa")
```
網址要設計!
不好的網址設計:
```
Rails.application.routes.draw do
resources :boards do
resources :posts
end
end
```
如果只是要找文章,不需要去找到boars_id,因為在Posts的資料裡面post.id不會重複。
進階的寫法:把文章包進看板裡,把不需要的功能抽掉
```
Rails.application.routes.draw do
resources :boards do
resources :posts, only: [:index, :new, :create]
end
resources :posts, except: [:index, :new, :create]
end
```
```
Rails.application.routes.draw do
resources :boards do
resources :posts, shallow: true
end
```
## 第四天
### 如果上層被刪掉了,那下層的資料怎麼辦?
* 資料有相依性
* rails 預設若下層有fk(forgin key)指向上層,上層砍不掉!
* 有dependent方法 :delete :destroy :nullify
```
class Board < ApplicationRecord
acts_as_paranoid
has_many :posts, dependent: :destroy
validates :title, presence: true, length: {minimum: 2}
```
其實用了paranoia,因為不會真的刪除資料,所以dependent有無設定根本不會觸發。
### 資料:實體層跟抽象層?
* 實體層:打開SQL軟體看到、設定的東西,都是實體層
### 驗證資料
#### 想要產生文章流水編號
```
list = [*'a'..'z',*'A'..'Z',*1..9]
list = list - [I','l',1,'o','O','0']
list.sample(8).join
```
#### uniquness,資料某欄位不能重複
1. 配合scope
```
class Holiday < ApplicationRecord
validates :name, uniqueness: { scope: :year,
message: "should happen once per year" }
end
```
name或是year必須是uniq。
2. case_sensitive 大小寫是否有區分
```
class Person < ApplicationRecord
validates :name, uniqueness: { case_sensitive: false }
end
```
## 加入了文章流水號,驗證設置成必須填入,且不能與其他資料重複後......
### 新的資料再也寫不進去了!
因為seial_generator是設定在before_create,所以在寫入時,在驗證階段時因為文章流水號都是nil,跟之前前面新增的文章重複了,所以寫不進去了!
[Callback回呼流程](https://railsbook.tw/chapters/19-model-validation-and-callback.html)
![](https://i.imgur.com/Vj9hF1M.png)
### 要寫rake,請系統幫忙做全域的更新!
寫在 lib/task/xxx.rake裡
**注意:執行rake task前,vaildates那邊必須先allow_nil: true**
過程:rake 先把資料塞進去,但還沒save,所以在驗證時狀態還是nil,會失敗!
```
namespace :db do
desc "更新文章序號"
task :update_post_serial => :environment do
puts "-----------------"
puts " updating serial "
puts "-----------------"
Post.where(serial: nil).each do |pt|
pt.update(serial: serial_generator(10))
print "."
end
puts "done!"
end
private
def serial_generator(n)
[*'a'..'z', *'A'..'Z', *0..9].sample(n).join
end
end
```
呼叫方法時,要看recicever是誰 方法只會找同層的
private 方法不能明確指出recicever是誰
### recicever
各個self會印出誰?
![](https://i.imgur.com/WW4fWJk.png)
method_missing
掙扎
我們看到的錯誤訊息其實是上上上..層的一個methd_missing的一個方法!
## 使用者!
> 資料正規化
> 讓每個資料表存放他該有的資料就好!
> 盡量不要有重複的資料,如果大家輸入的資料重複性很高,不如做另一個表格用代號的方式給他。
>
> 第一正規化(1NF):
> 一個欄位只能有一筆資料!
>
>
> 第二正規化(2NF):
> 1. 滿足1NF
> 2. 去除部分相依性
>
> 第三正規化(3NF):
> 再看看有沒有重複的資料欄位!
### 分析資料!
model: User
- account:string
- password:string
- email:string
- nickname:string
- gender:string
- state:string
- deleted_at:datetime:index
model: Profile
- 簽名檔
- 名片檔
`add_reference :post, :user`