# Rails
###### tags: `Rails`
### ==專案記錄==
- ++test\test_01++
已上 github 測試
- ++test\cart_415a++
使用 postgresql 的購物車程式,已用 git 版控
- ++test\cart_416c++
使用 postgresql 的購物車程式,可加減數量,已用 git 版控
- ++ruby\task\book_v2++
測試 tailwindcss 和 daisyUI
- ++ruby\vote_me++
線上課程範例
---
4/21
優先把購物車的介面刻出來
用cartproduct(parent去撈saleinfo的id與資料)用find_by找
後續要接user_id
---
1. 建立新的 Rails 專案:
rails new 專案名稱 --database=postgresql
cd 專案名稱
2. 建立資料庫:
rails db:create
---
### 3/21
- `gem install rails -v 6.1.7.3`
`rails -v`
`rails new jobbank`
`rails _6.1.7.3_ new jobbank`
- `ubuntu 20.04`
`wsl --list --verbose`
`wsl --set-version Ubuntu-20.04 1`
`Ruby 3.2.2`
`Rails 6.1.7.3`
`Node 16`
`npm install -g yarn`
- 加 readme 資料
語意化版本
- `gem install XXXX` <= Gemfile/Gemfile.lock
`gem uninstall XXXX`
- 全部安裝
`bundle install`
自動下載某個套件
`bundle add XXXX`
`yarn add / npm install`
- Ctrl+p 可以搜尋
- 連結資料庫(migrate),這個指令不會重作
`rails db:migrate`
若想清除需要使用以下指令 (倒退一步)
`rails db:rollback`
---
### Rails的規則,table會小寫+複數s
| Model | Table |
| -------- | -------- |
| Book | books |
| Student | students |
| Rusume | resumes |
- 慣例優於設定(COC),不要重複code(DRY)
- 後續想要加新欄位,正確的做法應該開一個新的migrate
`rails g migration 修改說明文字` (g=generate)
`rails d migration 修改說明文字` (刪除)
- `rails -T` 可看Rails有哪些指令
- 在vscode內的 view > source control 可顯示GIT符號
- 看誰用了3000 port 並砍掉
`lsof -n -i:3000 | grep LISTEN`
`kill 754`
### 在rails內新增model
- `$ rails g model Resume name:string email:string tel:string skill:string intro:text city:string education:text experience:text portfolio:text`
上面為完整指令,若資料為 string 型別可以省略,以下為省略後指令
- `$ rails g model Resume name email tel skill intro:text city education:text experience:text portfolio:text`
---
### 換 node 16 執行流程
1. 換用 node 16
2. 刪除 node_modules 目錄
3. 執行 yarn install -> 產生新的 node_module
4. 重開 rails s
### 在 nvm 中安裝 node 16
- `nvm install 16.19.0`
使用 node v16
`nvm use 16`
查詢 node 版本
`nvm ls`
設定預設 node 版本
`nvm alias default 16.19.0`
### 3/21 rails 進度
* `$ rails new ____`
`$ rails g model ____`
`$ rails g migration ____`
`$ rails db:migrate`
`$ rails db:rollback`
`edit routes.rb`
`$ rails g controller ____`
`edit controller ____`
`add app/____/views/___.html.erb`
### 檔案位置
* `migrate:db > migrate`
`routes.rb:config > routes.rb`
`xxxx_controller.rb:app > controllers > xxxx_controller.rb`
`zzzz.html.erb:app > views > xxxx資料夾 > zzzz.html.erb`
### Rails Route
* 設定首頁路徑
`root "welcome#index"`
把"/users"轉址到"/accounts"
`get '/users', to: redirect('/accounts')`
- 在Route進行比對的時候,在前面先查到的就會先生效
- 在route內使用resources可一次製作8個路徑,如下
```ruby=
Rails.application.routes.draw do
resources :users
end
```
| Prefix | Verb | URI Pattern | Controller#Action |
| --------- | ------ | ------------------------ | ----------------- |
| users | GET | /users(.:format) | user#index |
| | POST | /users(.:format) | user#create |
| new_user | GET | /users/new(.:format) | user#new |
| edit_user | GET | /users/:id/edit(.:format)| user#edit |
| user | GET | /users/:id(.:format) | user#show |
| | PATCH | /users/:id(.:format) | user#update |
| | PUT | /users/:id(.:format) | user#update |
| | DELETE | /users/:id(.:format) | user#desroy |
* 若不需要8個路由,可使用以下指令修改
```ruby=
Rails.application.routes.draw do
resources :products, only: [:index, :show]
```
* 或是反過來這樣寫也行
```ruby=
resources :products, except: [:new, :create, :edit, :update, :destroy]
end
```
### rails c (控制台模式)
* exit / ctrl + d
(離開)
Post.first
(顯示第一篇文章的資訊)
Post.all
(顯示全部文章的資訊)
p1 = Post.first
(取得第一篇文章)
p1.user
(找出該篇文章的作者)
u1 = User.first
(取得第一個會員)
u1
(列出第一個會員的資料)
u1.name
(列出第一個會員的name)
u1.email
(列出第一個會員的email)
### 下拉式選單
* 在veiw的html.erb內,可做下拉式選單列出所有user
```rbuy=
form.label :user_id
form.collection_select(:user_id, User.all, :id, :name)
```
### 解決 N + 1 問題 (重複撈資料造能效能浪費問題)
* 在controllers的posts_controller.rb內,可在撈文章時順便撈使用者名稱,改寫如下 (上→下)
`@posts = Post.all`
`@posts = Post.all.includes(:user)`
### 驗證器
* 希望名字 / email不能填空白
在 controllers 的 user_controller.rb 內加上
`validates :name, presence: true, length: { in: 6..20 }`
名字長度在 6~20 字之間
`validates :email, presence: true`
(驗證欄位必須要填資料,若空白則跳錯 "name / email can’t be blank")
---
### 3/23
- Route
- xxxx_path vs xxxx_url
- xxxx_path 優缺點
- link_to
- Form
- <form action method>
- GET vs POST
- HTTP 狀態
- <%= form_for %>
- 保護機制
- AuthenticityToken
- skip 驗證(小心用)
- 給 token
- 用 form_for
- ForbiddenAttributeError
- 用 permit
### 局部渲染
* `<%= render 'shared/navbar' %>`
`shared > _navbar.html.erb` (額外新增的模組檔名前要加底線) 用的時候不用加底線
- 文字判斷可用regex(101)
- 一般的搜尋網頁功能都用get做,例如google搜尋引擎
post 傳送資料不會顯示在網址列上
- http狀態
204 not connect
404 not found
- 串接金流時可能會skip authenticity_token(驗證),其他情況不建議skip
- 打debugger可下中斷點
可打參數測試
`params`
`params[‘resume’]`
---
### 3/27
- `rails c --sandbox `
控制台(沙盒模式) 離開會清除設定
`r1 = Resume.new`
`r1.save` =>false
`r1.errors.any?` =>true
`r1.errors.full_messages` =>列出所有錯誤
* 用間接給參數 達到模組化 重複利用
局部渲染 erb 內不要放實體變數 (@xxxx),可以用餵的方式給他,以下使用廣告為例
```ruby=
<%= render ‘shared/ads/square’, content: @ad1 %>
<%= render ‘shared/ads/banner_large’, content: @ad2 %>
<%= render ‘shared/ads/banner_small’, content: @ad3 %>
```
### clone github上的專案
- 在終端機下指令
`git clone https://XXXXXX.git`
專案連結在github綠色按鈕內的http下複製
- 在 github 下載完專案後
`bundle install`
`yarn install`
`rails db:migrate`
`rails s`
---
### 3/28
- rails 錯誤訊息頁面下方可以打字
例如 "params"
- 有動態id的router系統不會給名字 要自己取
有相同路徑時不用再給一次 as
- Query String
`/resume/123?a=1&b=2`
- "?"前面的是路徑,後面是id資料
- `.where` 會撈出多筆資料,並放進一個陣列
`.find()` 只能找出一筆資料
`.find_by(number)` 只能找出一筆資料
- `rescue_from`是rails提供的功能 可處理錯誤訊息
- `Turbolinks`是加速連結的rails功能,可能造成某些 javascript損壞
- 要有表單才能做POST
- 局部渲染其他檔案時,檔名前需要加底線
`<%=render 'resumes/data' %>`
若是要渲染有相關的檔案,可以不用寫資料夾名稱
- 作業 (已完成)
用 Rails new 一個專案
book 的 CRUD,書名(name)、作者(author)、簡介(introduction)
25分鐘完成
---
### 3/30
- resources 和 resouce 產出的路徑差別為,前者有id,後者沒有
collection 和 menber 可建立路徑,前有無id後者有id
- annotate 套件,可在model備註資料
- ruby 使用 digest 函式庫需要 `require 'digest'`
- `self.password` 的 self 指的是自己本身,而非類別變數,self.password 指的是一個欄位,把左邊前面的 self 拿掉會變成區域變數,就不會生效了
- devise 套件 可快速做 會員登入/查詢密碼 功能
- hash 取值時要填 `keyword:`
- paranoia 套件 可快速設定軟刪除
---
### 3/31
- 增加 migrate 檔案需要使用指令
- Authentication 認證、憑證
Authorization 授權
- pundit 套件 可處理憑證/授權問題
- foreman 套件 可一次開啟多個server
`bundle add foreman` 安裝 foreman
`foreman s` 使用指令開啟 server
- 建立一個`Procfile.dev`檔案,內容如下
`web: rails server -p 3000`
`webpack: bin/webpack-dev-server`
`css: bin/rails tailwindcss:watch` (tailwindcss使用)
- 建立一個`.foreman`檔案,內容如下
`procfile: Procfile.dev`
---
### 4/6
- rake
`rake task` 可幫忙自動生產履歷
`rake -T` 可查看 rake 指令
- tailwind
回去測試 `tailwind` 的使用方式,可查看官網和上課影片安裝,可取代傳統 css
- 看 form_for 和 form_with 的用法與差異
- `rails routes -c xxxxx` 查詢跟 xxxxx 相關的路徑
- 在新增路徑時,加上 `shallow` 可以自動做出縮短路徑的巢狀結構
- comment 同時與 resume 和 user 產生關聯,給資料時兩個同時都要給
- js.erb
在 rails 中寫 js 時,render 時在 "" 中加 `j` 可跳脫 單引號和雙引號
- 設定變數時要使用`var`,不然重複宣告變數會出現錯誤
- `stimulus` 方便使用 js 的套件
- 用 `bin/dev` 開 server
---
### 4/7
- foreman 套件 可一次開啟多個server
`css: bin/rails tailwindcss:watch`
- action table 互動式聊天室窗套件
- hotwire 可對 html 的取用進行優化
- turbo-frame 可立即在目前的視窗顯示其他視窗的內容
trubo-stream 刪除可用,也是立即更新
- delete-at 刪除使用套件 (軟刪除)
- thubmb 套件 可快速使用各種向量圖
要先裝 fortawesome
- axios 套件 用來代替 fetch
- rubocop-rails 套件 整理程式碼
`rubocop -A` 自動修正程式
---
### 4/10
- friendly_id 套件 優化網址路徑
`rails g magration add_liug_to_users slug:uniq`
- Rails Internationalization (I18n) 多國語系
- sortableJS 套件 各種拖曳物件效果
- acts_as_list 套件 拖拉排序用套件
- rails_request.js 套件
- ngrok 套件 可產生一個臨時的網址,用來測試金流或其他功能
---
### 4/11
- braintree 串 paypal 金流
測試卡號:4111-1111-1111-1111
- dotenv 可存放變數(token)
- aasm 狀態機套件
- kaminari 分頁套件
---
### 4/17
- carrierwave 套件 上傳圖片
- active storage
- Amazon S3 放照片的地方
- marked 套件
---
### Docker
- image (only read)
- `container = image.new`
- `docker run hello-world`
- `which docker`
- `docker image ls`
查看電腦裡有哪些image
- `docker container ls`
查看電腦裡有那些正在執行的
- `docker container ls -a`
- `docker run nginx`
- `docker run -p 777:80 nginx`
將localhost port 777 對到 外部的port 80
- 連到 `http://localhost:777/` 會有 nginx 的預設頁面
`docker run -v ${PWD}:/user/share/nginx/html -p 777:80 nginx`
- `docker run -it nginx /bin/sh`
可打字互動 不要執行預設行為
- `docker build -t`
---
### 4/18
- rails 7 import maps hotwire
- rails g stimulus
- polymorphic 多型關聯
- STI single type ixxxx 單一表格繼承關聯
- 在 model 中不要亂用 type 當欄位
---
### 4/20
- 使用hotwire時,turbo預設會打開,若無法開啟網頁可關閉
`data: { turbo: false }`
- 到 `config/initializers/inflecions.rb` 檔案內
解開第6行 `ActiveSupport::Inflrctor.inflections(:en) do |inflect|`
解開第11行 `end`
改第9行的 `inflect.irregular 'aaa', 'bbb'`
設定 rails 專案內的 aaa 複數為 bbb
---
### vote_me 線上課程
* 建立候選人的 magration
`rails g model Candidate name party age:integer politics:text votes:integer`
* 建立選票的 magration
`rails g model VoteLog candidate_id:integer ip_address`
改寫為下面方法,效果與上面相同
`rails g model VoteLog candidate:references ip_address`
* `candidate:references`
此寫法會產生一個 candidate 的 id 欄位,會參照指向候選人的 id (references為複數)
* `rails c` 開控制台
`VoteLog.all` 查詢所有投票記錄
`VoteLog.count` 查詢投票數量
`c1 = Candidate.first`
`c1.vote_logs` 第一個候選人的投票記錄
`c1.vote_logs.count` 第一個候選人的票數
* Counter Cache 可在數據庫做一個簡單的計數器,減少資料庫的存取
- 在資料表中增加一個欄位
`rails g migration add_counter_cache_to_candidate`
- 在 migration 表內增加欄位資料如下
```ruby=
class AddCounterCacheToCandidate < ActiveRecord::Migration[6.1]
def change
add_column :candidates, :vote_logs_count, :integer, default: 0
end
end
```
- 執行 `rails db:migrate`
在 `model/vote_log.rb` 內增加資料 `counter_cache: true`
會在寫入票數的同時,去 `vote_logs_count` 欄位更新票數
- 在 `veiw/cansidates/index.html.erb` 內增加 `<td><%= candidate.vote_logs_count %></td>`