ASTRO Camp 7th
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Owners
        • Signed-in users
        • Everyone
        Owners Signed-in users Everyone
      • Write
        • Owners
        • Signed-in users
        • Everyone
        Owners Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights New
    • Engagement control
    • Make a copy
    • Transfer ownership
    • Delete this note
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Note Insights Versions and GitHub Sync Sharing URL Help
Menu
Options
Engagement control Make a copy Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Owners
  • Owners
  • Signed-in users
  • Everyone
Owners Signed-in users Everyone
Write
Owners
  • Owners
  • Signed-in users
  • Everyone
Owners Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       Owned this note    Owned this note      
    Published Linked with GitHub
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    # 0408 錯誤驗證、原始碼簡化 ###### tags: `Ruby / Rails` ## 課前思考 龍哥的短網址服務系統:[https://ubin.io/](https://ubin.io/) (系統還有些問題待修) 可以輸入網址,做出 6 碼的短網址: https://ubin.io/zxCSrG -> https://5xruby.tw/ https://ubin.io/u7kmzE -> https://kaochenlong.com/ 如果是亂打的網址: https://ubin.io/abcdefg -> 因為資料庫裡沒這個資料,會出現「不存在」頁面(404) 除了短網址外,也有一般的靜態頁面: https://ubin.io/about https://ubin.io/contact https://ubin.io/privacy 如何在 `routes.rb` 裡設計出這樣的功能? 程式在跑路徑時為由上往下比對,比對到了就結束 - 建議將特定的路徑放在上方 - 把須對應用的方法放最後面 `get ':id', to: 'urls#show'` ```ruby= get '/', to: 'urls#index' root 'url#show' #同等上方(因為太常用所以 rails 直接內建功能)` ``` 環境變數 在這份code看不到的 在建立後台管理系統的時候,把路徑設成一個亂數或非 admin 的網址 => (見先修教材 namespace 部分) --- ### admin interface ```ruby= namespace :admin, path: ENV['admin_path'] root 'pages#dashboard' end ``` * 關於api的命名方式建議: * /api/books/json * /api/v1/books/json * /api/v2/books/json * 推薦加上版本的寫法,因為可以更新版本但同時保留之前的版本給不願意更新的人繼續使用 **應用程式介面**(英語:**A**pplication **P**rogramming **I**nterface,縮寫為**API**,是一種計算介面,它定義多個軟體中介之間的互動。 API 手冊範例:[藍新金流 API 串接](https://www.newebpay.com/website/Page/download_file?name=%E8%97%8D%E6%96%B0%E9%87%91%E6%B5%81NewebPay_%E5%96%AE%E7%AD%86%E4%BA%A4%E6%98%93%E7%8B%80%E6%85%8B%E6%9F%A5%E8%A9%A2%E4%B8%B2%E6%8E%A5%E6%89%8B%E5%86%8A%20V1.0.5.pdf) API 串接: 由前端直接處理太危險 會從前端打資料到後端,從網站後端把資料打包外加金鑰打入金流系統的 api,金流系統處理之後在將回應傳會本地系統後端 短網址範例:[Lihi.io AB 分流短網址](https://lihi.io/) 金流系統主流:紅藍綠 三家廠商 [基本常識介紹](https://hsienblog.com/2017/07/17/%E7%B4%85%E9%99%BD%E7%A7%91%E6%8A%80-%E7%B6%A0%E7%95%8C%E7%A7%91%E6%8A%80-%E8%97%8D%E6%96%B0%E7%A7%91%E6%8A%80-%E9%87%91%E6%B5%81%E6%9C%8D%E5%8B%99%E5%95%86%E6%AF%94%E8%BC%83/) 金流二房東:幫助使用者繞過紅藍綠的審查,直接使用金流 API 系統,幫助串流,簡單好用還可以分期,訂單在平台上 同時儲存使用者需要的訂單資料、同時比對金流 金流二房東範例:[貝殼集器](https://backme.tw/) 網址二房東範例:[Heroku](https://www.heroku.com/) docker:協作平台檔案,輕量化的虛擬器,從作業系統版本、處理器...,讓不同工程師在同一個平台工作,再直接整包連平台推送上架,避免因環境配置不同產生功能壞掉等麻煩。 --- 在 form 裡面取得的東西會被整理成 hash input 裡面的 name="restaurant[tel]" 轉換成 restaurant => { tel => value } 可使用 params[:restaurant] 來取用 --- ![](https://i.imgur.com/jCdEIcp.png) redirect_to 也是一種 render,如果同時使用會得到 double render 的錯誤訊息 ```ruby= def create # 寫入資料庫 render html: params[:restaurant] redirect_to '/restaurants' end ``` - rails 內建把 password、authenticity_token 隱藏掉(只顯示 filtered)避免敏感資訊被存入 log file 內 - 會被過濾掉的關鍵字: ```ruby= 2.6.5 :001 > Restaurant.filter_attributes => [:passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn] ``` - [Rails 6 更新功能](https://bigbinary.com/blog/rails-6-adds-activerecord-base-filter_attributes) new 方法:把 params 存到記憶體 save 方法:把記憶體存起來的東西放到資料庫中 create 方法: new + save 一起做 範例: ```ruby= @restaurant = Restaurant.new @restaurant.save 等同 @restaurant = Restaurant.create ``` --- ![](https://i.imgur.com/VsAQO1Y.png) 這個錯誤訊息為,想要將一包資料透過model寫進資料庫,但他沒有經過過濾檢查,仍舊可以經過改寫html而產生新的資料送出,所以資料沒有經過清洗就會得到這個錯誤訊息 架站金句:把每個使用者都當成有惡意的笨蛋 架站除錯句 1. 打一個中斷點 2. 在要除錯的地方插入原始碼 `debugger` 或 `byebug` 或`pry` 3. 會停留在 `debugger` 的下一行程式碼 4. 可以在終端機確認各種變數的值 5. 會造成無窮迴圈,如果要離開就在終端機輸入 continue 或 c 可以使用 strong parameter 方法將只被允許資料送出 ```=ruby private # 讓檔案中所有方法都可以取用但是在外部不能更動 def restaurant_params params.require(:restaurant).permit(:title, :tel, :address, :email, :description) end ``` ### strong parameter => 面試常考題 - 解釋定義 - 功用 - 什麼時候該用、為什麼 - [Strong Parameters](https://rails.ruby.tw/action_controller_overview.html#strong-parameters) #### 所有網路上傳輸的東西都是「文字」 ## 錯誤驗證 驗證規則通常會直接放在 model 裡面(但通常不會放在同一個地方??) 使用 validates 方法 ```ruby= class Restaurant < AoolicationRecord validates :title, presence: true validates :email, presence: true validates :title, :email, presence: true, uniqueness: true # uniqueness 表示這個項目得到的值在這資料庫只能存在一個 # 舊版寫法: validate_presence_of :title, :email end ``` 建議驗證的項目各自存在 [「Rails Guide - Validations 各種驗證器 from 官方」](https://guides.rubyonrails.org/active_record_validations.html#uniqueness) 客製化的驗證器寫完之後用 `validate :方法名稱` 來呼叫 普通 rails 內建的驗證器都使用 `validates...` 直接呼叫 (注意單數複數) 提醒使用者該輸入的資料:前端設定 placeholder ### 查看錯誤訊息 - r.errors => 建立 errors 這個 key - r.errors.any? => 確認 errors 是否有 value - r.errors.full_messages => 顯示 errors 內所有訊息 實用範例:(印出實際錯誤訊息) ```ruby= # 在渲染的時候跑出來 # 配合上方驗證資料是否存在使用,顯示是否有錯誤訊息 # 可以使用在 new.html.erb => 在 submit 出去有錯誤訊息產生回到 views/new 的時候顯示 # 也可以放在 edit.html.erb 裡面 # 依照頁面需求使用 <% if @restaurant.errors.any? %> <ul> <% @restaurant.errors.full_messages.each do |message| %> <li><%= message %></li> <% end %> </ul> <% end %> ``` 排序資料跟選取資料室資料庫的強項,Ruby 的弱項 關於處理資料的功能要用資料庫直接處理 `.all` 方法其實是不知道要用什麼的時候使用,如果知道特定用途的話可以直接指定使用的方法 * 反向排序:desc / descending * 正向排序:asc / ascending ```ruby= @restaurants = Restaurant.all.order(id: :desc) # 這邊的.all 可省略 @restaurants = Restaurant.where(title: 'aaaa') # 只拿出 title 為 aaaa 的資料 ``` ### link_to 方法 ```htmlembedded= <% @restaurants.each do |restaurant| %> <%= link_to restaurant.title, "/restaurants/#{restaurant.id}" %> # 不建議使用,明顯是硬湊 <%= link_to restaurant.title, restaurants_path(restaurant.id) %> # 不建議使用,因為.id可以不用寫 <%= link_to restaurant.title, restaurants_path(restaurant) %> # 建議使用 <%= link_to restaurant.title, restaurant %> #建議使用,前提理解restaurant在rails的運作模式 ``` 在 data: {} 裡面的東西會被加上 data-(輸入值) 傳到 html 中建立屬性 因為`method: 'delete'`太常見,所以常會放在外面 好處是會有 `nofollow`(For 爬蟲) ```ruby= <%= link_to '刪除', restaurant_path(restaurant), method: 'delete', data: { confirm: '確定嗎' } %> ``` 也可以寫在裡面,一樣會生成 `data-method / data-confirm` ```ruby= <%= link_to '刪除', restaurant_path(restaurant), data: { method: 'delete', confirm: '確定嗎' } %> ``` ### 找尋資料方法 `.find` - 後面的條件只能帶 id - 找不到會直接跳錯誤訊息 `.find_by` - 後面的條件可以帶條件,但最終只能找一個 - 找不到會回傳 `nil` 範例: ```ruby= def show @restaurant = Restaurant.find(params[:id]) 或 @restaurant = Restaurant.find_by(id: params[:id]) end # 讓外部使用者不會直接看到錯誤畫面的方法 def show begin @restaurant = Restaurant.find(params[:id]) rescue # 把可能會出錯的語法先包起來 #begin~rescue錯誤的話就執行下方 redirect_to restaurants_path else # 加 else 代表不管有沒有出錯都會執行 (某些程式使用 finally) ...... end end # 範例 def show begin #表示包起來的地方可能會壞,處理例外訊息 # 開啟檔案 rescue # 跳出錯誤訊息 else # 關檔 # 不管有沒有成功開啟檔案,都要關閉檔案 end end # 範例 def show begin #表示包起來的地方可能會壞,處理例外訊息 @bar = Bar.find(params[:id]) rescue render html: "error" else #某些程式語言叫做final ........ #不管有沒有我都要做這件事 end #若只有一個方法的話可以省略begin-end end ------------------------------------------------------- # 直接在源頭攔截錯誤頁面 (在特定 controller 最上方寫入) rescue_from ActiveRecord::RecordNotFound, with: :not_found # 原為 rescue_from(ActiveRecord::RecordNotFound, {with: :not_found}) private def not_found redirect_to restaurants_path # 消極地把頁面轉去首頁 或 render file: "#{Rails.root}/public/404.html", #404絕對路徑 #要記 status: 404 # 原為 render({file: "#{Rails.root}/public/404.html", status: 404}) end # 可直接將層級提高到所有 controller (把方法整個移到 application_controller.rb) ``` - `begin` `rescue` 跟 `end` 要成對出現 - 如果沒有 else 的話,兩個可以一起省略 Exception 例外 Error 錯誤 - 通常在 controller 裡面放 action 時 - index 跟 show 放一起 - new 跟 create 放一起 - edit 跟 update 放一起 - 在 controller 裡的 action 最後如果==沒有==放 render :頁面 的話 - 框架會跑到 views 裡面去找同名的檔案拿來做渲染 在 rails 裡面用 destroy 方法時會讓 HTTP method 用 DELETE 傳出 request => 但是 rails 其實會直接把 request 先轉成用 POST 傳出,然後在資料中塞入 _method: delete 達成一樣效果 (防止瀏覽器支援問題產生) 在 html 標籤中如果加上開頭為 data 的屬性,結果不會被渲染出來 => Unobtrusive JavaSctipt (UJS) 不打擾屬性的 JS 在 rails 環境底下會有一支 JS 程式在監視: - 如有 data-method 的話會把 HTTP method 改成指定的方法傳出 - 如有 data-confirm 的話會建立彈出確認視窗 - 跳出後按"是"傳回true,按"否"傳回 false ## 將重複的原始碼簡化 1. 在後方建立方法,並在需要的地方統一帶入 2. 一樣建立方法後,在開頭使用 before_action 方法直接套用 - before_action :find_restaurant (自訂的方法名稱), only: [:show, :edit, :update, :destroy] - 在 controller 內寫入,表示action會先執行這個方法,指定的方法會直接先套入再繼續執行 (通常會放在最上方,放在哪都好,但不要包到private裡或別的方法裡) - 如果同時有兩個 before_action,則會由上而下依序執行 - 在後面加入 only 跟 except 可以讓該動作用指定的條件套入 --- 在 view 裡面再做渲染:partial render 局部渲染 在 views 資料夾中的檔名要加底線,e.g. `_form.html.erb` 在另一個 views 裡呼叫時不加底線,e.g. `<%= render 'form' %>` 不建議在 partial render 的檔案中放入實體變數 通常會: 1. 在檔案中放入區域變數(標準化 partial render 檔案) 2. 在呼叫檔案的時候將區域變數帶入相對應的實體變數 `<%= render 'form', restaurant: @restaurant %>` --- ## 題外話 ### SQL 語法 ```sql= SELECT * (列名稱) FROM restaurant(表格名稱) WHERE title like '%a%' ``` - 星號 * 是選取所有列 - `'a%' `是指找a開頭的資料 - `'%a'` 是指找a結尾的資料 - `'%a%'`是指找a開頭或a結尾的資料 ```ruby= @bar = Bar.all.where(title like '%a%') #只要開頭是a的都會找到,包含aa, aaa ``` --- ### 資安常見問題 - [SQL injection (SQL 注入)](https://zh.wikipedia.org/wiki/SQL%E6%B3%A8%E5%85%A5) - 資安問題,利用資料庫語言特性,讓外部使用者可以直接存取所有資料庫內容 - 通常框架會設定特殊方法清洗輸入指令,避免 SQL 注入的狀況產生 - [CSRF 跨站請求偽造](https://zh.wikipedia.org/wiki/%E8%B7%A8%E7%AB%99%E8%AF%B7%E6%B1%82%E4%BC%AA%E9%80%A0) - 資安問題,rails 會透過 CSRF token 防範此種攻擊 - 一種挾制使用者在當前已登錄的Web應用程式上執行非本意的操作的攻擊方法。 --- ### PUT vs. PATCH - `PUT` :把資料整包換掉 - `PATCH` :把資料的一部份抽換(補丁的概念) --- ### 進入 rails 主控台 1. 進入 Terminal 2. 在 rails 專案資料夾內輸入 `$ rails console` ( 也可用 `$ rails c` ) - 沙盒模式 - 將步驟 2 改成輸入 `$ rails c --sandbox` - 進入 rails 主控台但是在離開的時候把所有更動還原到進入前的狀態

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully