Hello, everyone!
終於可以進入下個階段囉!被翻爛的書今天想用新的專案練習Active Record 基本的query methods,並嘗試用SQL methods 來呈現及比較用法。由於自己是SQL 魯蛇,因此要特別留心method 的形態、單複數、大小寫等,那就讓我們開始吧!
首先我們來試試看取出User.first.email:
irb(main):021:0> User.first.email
  User Load (0.6ms)  SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT $1  [["LIMIT", 1]]
"Sincere@april.biz"
這是Active Record 的data access method;可如果是利用SQL 可以怎麼寫呢?
我們先來組裝基本的語法:
SELECT * FROM users
#  ↓
SELECT * FROM users WHERE id = 1 
#  ↓ 
SELECT email FROM users WHERE id = 1 
我們試試看將SQL 丟到console 執行:
sql = "SELECT email FROM users WHERE id = 1"
# 目前查到了兩個比較適合的語法:
# 方法1
irb(main):031:0> ActiveRecord::Base.connection.exec_query(sql).rows
  SQL (0.7ms)  SELECT email FROM users WHERE id = 1
[
    [0] [
        [0] "Sincere@april.biz"
    ]
]
# 方法2
irb(main):032:0> User.find_by_sql(sql)
  User Load (0.7ms)  SELECT email FROM users WHERE id = 1
[
    [0] #<User:0x00007f94196c2fa0> {
           "id" => nil,
        "email" => "Sincere@april.biz"
    }
]
先稍微觀察、研究這兩個方法回傳的形態是什麼:
irb(main):042:0> ActiveRecord::Base.connection.exec_query(sql).class
  SQL (0.8ms)  SELECT email FROM users WHERE id = 1
ActiveRecord::Result < Object 
irb(main):044:0> User.find_by_sql(sql).class
  User Load (0.9ms)  SELECT email FROM users WHERE id = 1
Array < Object
有點混亂,但我們先查查第一個方法是來自哪(ActiveRecord::Base.connection.exec_query);
接著會看到一個很熟悉的字眼ActiveRecord::Base,這不是在app/models/application_record.rb出現過嗎:
class ApplicationRecord < ActiveRecord::Base
  self.abstract_class = true
end
進去看了一下才發現有這東西:
下方的文字說明也在Rails Guide 看到,雖然水好像很深;之後再沿線搜尋,會找到這是個Active Record 的module ActiveRecord::ConnectionAdapters::PostgreSQL::DatabaseStatements
Public Instance Methods

看起來是用丟SQL 語法進去,回傳一個處理後的ActiveRecord::Result XD
而ActiveRecord::Result又是什麼呢:This class encapsulates a result returned from calling #exec_query on any database connection adapter.
是個會處理及回傳封裝後結果的類別
再去看看他的initialize方法:
def initialize(columns, rows, column_types = {})
  @columns      = columns
  @rows         = rows
  @hash_rows    = nil
  @column_types = column_types
end
大概是將SQL 處理的結果根據資料表的欄、列回傳個hash 吧 XD
整理一下,ActiveRecord::Base.connection.exec_query(sql) 應該是:
嗯... 好像有看沒有懂,且回傳的結果有點雜,自己沒有很喜歡...
但,明天再繼續研究第二個方法User.find_by_sql(sql) 的由來好了 XD
今天的研究就到這結束吧,謝謝大家~