怎麼用 Ruby 語法查詢資料?
find
find 方法只能使用 primary key(id) 值來查找,也就是從 id 去找,
返回查詢對象或拋出 exception(例外訊息)!
exception 意即:如果找不到對應的記錄,則會拋出 ActiveRecord::RecordNotFound 錯誤。
1 | # Find the article with primary key (id) 6. |
轉換成 SQL 語法:
1 | SELECT * FROM articles WHERE (articles.id = 6) LIMIT 1 |
也可以用陣列方式抓取多個 id:
1 | # Find the articles with primary keys 1 and 6. |
轉換成 SQL 語法:
1 | SELECT * FROM articles WHERE (articles.id IN (1,6)) |
Remark:
若不是所有提供的主鍵都有找到匹配的物件,則 find 方法會拋出 ActiveRecord::RecordNotFound。
有 exception(例外訊息)就可以使用 begin … rescue 來捕捉:
1 | def show |
find_by
find_by 方法使用 key: value 的 Hash 當作參數來查找記錄,
返回符合條件的第一個查詢對象或 nil。
1 | def show |
find_by!
find_by! 方法其實跟 find_by 差異在如果沒有查到符合條件的資料會回傳 exception(例外訊息)也就是 ActiveRecord::RecordNotFound 錯誤!
where
where 方法接收一個條件可以使用 字串、陣列、物件(key : value)作為參數,
並返回所有符合條件的查詢對象,是一個 ActiveRecord 查詢集合(Relation)。
如果找不到紀錄,會是一個空的 ActiveRecord 查詢結果 []。
Remark:
純字串的條件下,若字串內帶有變數,會有 SQL injection 的風險,所以通常會改用陣列處理!
1 | # 不推薦的寫法,容易有 SQL injection 的風險 |
# SQL injection
SQL injection 是一種常見的安全漏洞,發生在應用程式沒有適當處理用戶輸入的情況下。
當應用程式將用戶輸入直接嵌入 SQL 查詢中,而沒有對輸入進行適當的驗證和處理時,
攻擊者可以利用這一點注入惡意的 SQL 代碼,從而在應用程式的資料庫上執行未授權的操作。
假設一個應用程式接收用戶的輸入並將其直接嵌入 SQL 查詢中:
1
2
3
4
5
6# 抓取 user 輸入的值
user_input = params[:name]
# SQL 語法
sql_query = "SELECT * FROM users WHERE name = '#{user_input}'"
# 出來的結果會用 SQL 語法來抓
results = ActiveRecord::Base.connection.execute(sql_query)
如果用戶在輸入中插入惡意的 SQL 代碼,攻擊者可能會干擾 SQL 查詢的結構,
從而執行未授權的操作,例如刪除資料、查詢敏感資料或修改資料庫內容。
# SQL Injection Based on 1=1 is Always True
1=1 is Always True 就是所謂惡意的 SQL 代碼,
假如攻擊者在 user_input 輸入: Attacker OR 1=1
,
這時,攻擊者就可以在毫無驗證的情況下直接通過了,
這個 SQL 查詢的條件永遠為真,導致查詢結果返回所有用戶的資料,而不僅僅是符合用戶輸入的資料。
# 防止 SQL injection:
使用參數化查詢或預處理語句,而不是直接將用戶輸入嵌入 SQL 查詢中。
使用 Active Record 的方式處理條件,例如使用陣列方式處理:
1 | Model.where("name = ?", params[:name]) |
Rails 會將 ? 換成 params[:name] 做查詢。條件式後的元素,對應到條件裡的每個 ?。
where vs find_by
1 | # 使用 where 方法 |
Summary
- find 方法根據主鍵(id)值查詢記錄,並返回查詢對象,如果找不到則拋出例外訊息。
- find_by 方法以 Hash 參數來查詢記錄,返回第一個符合條件的查詢對象,找不到則返回 nil。
- find_by! 方法跟 find_by 類似,但如果沒有找到符合條件的記錄,它會拋出例外訊息。
- where 方法進行更複雜的查詢,它可以接收字串、陣列或物件(key: value)作為條件,並返回所有符合條件的查詢對象,是一個 ActiveRecord 查詢集合(Relation)。
使用純字串的條件時,為避免 SQL injection 風險,我們應該改用陣列方式處理。
參考資料:
➫ Active Record 查詢
➫ 【Ruby】每天一點 Rails:find()、find_by()、where()
➫ ActiveRecord中的find、find_by和where方法的差異在哪?
➫ SQL Injection