ruby on rails

ruby on rails

Rails使用 include 和 join 避免 N+1 query

Rails當中要連結model之間的關係非常簡單,不過也因為由於建立關係是這樣的簡便,造成許多指令會在讀取資料庫時有記憶體的浪費。例如我們建立以下關係: # Post has_many :comments # Comment belongs_To :post 並在helper中寫下: Comment.each do |comment| comment.post.title end 如果我們有很多個comment,就會產生非常多的資料庫查詢記錄: 每一筆查詢對資料庫的效能都是一種消耗,因此身為後端開發者,查詢資料庫的次數是越少越好。以上寫法讓我們在查詢post的title時都透過comment的關連去查詢,所以執行每一個comment時,都會查詢一次post,增加大量的資料庫查詢比數。這就是一般資料庫容易產生的N+1 query問題,意思是我們在迴圈當中大量查詢N筆資料,再加上開頭查詢的那1筆,稱為N+1。 為了避免在幾千筆資料查詢時大量消耗不必要的記憶體,Rails提供joins和include方法可以在第一次查詢時將所有我們需要的資料一次查完。 記住

ruby on rails

Rails 基本命名及關連

剛開始進入Rails,對於命名這件事情一定非常不習慣。之所以命名這麼重要,也是因為Ruby是物件導向的語言,而Rails更是把許多class、module、method都拆散在不同檔案中,方便管理。如果沒有將命名處理好,很容易不知道一個method是拿來做什麼用的。 以下說明幾個基本命名原則,讓新手可以更快掌握。 檔案命名與呼叫名稱 首先,檔案名稱都是小寫並加上底線(underscore): posts_controller.rb 但在呼叫這個class時,是用大寫,也就是CamelCase,跟駱駝的背部一樣有很明顯的高低起伏: PostsController 所以如果你在檔案名稱上看到大寫,最好趕快改成小寫並加上底線。資料庫的table名稱、column名稱也建議都是使用全小寫加上underscore的命名方式。 Model 首先,在command line中產生model,要使用單數。想像model是一個table的名稱,所以用單數來當做整體的概念。 $ rails generate model post 而在一般controller或其他地方呼叫

ruby on rails

Rails複製資料庫內容:開發環境 -> 測試環境

進行Rails開發時,有時需要將開發環境(development)的資料庫內容複製到測試環境(test)當中,方便我們在整合測試時,有時需要撈取一些特定資料。我們這次要利用db:seed的方式,指定將資料seed到測試環境的資料庫當中。 分成三個步驟: 1. 開設一個專門的seed資料夾 2. 將目前的開發環境資料庫內容複製到seed檔案當中 3. 利用db:seed將資料倒入測試資料庫中 1. 開設專門的seed資料夾 由於會有許多測試檔案,因此我們不動到原本rails內建的db/seeds.rb,另外再開一個新的資料夾,放入所有我們需要的seed檔案。我們可以在db底下再增加一個資料夾seeds。整個結構變成: db |--> seeds |----> posts.rb |----> comments.rb 裡面所有的.rb檔案就是我們要產生的seed檔案。 2. 使用gem 'seed_dump' 來複製資料

ruby on rails

RSpec-Rails當中自訂methods及helpers

在RSpec當中,常常會有些瑣碎的東西需要重複輸入,尤其是unit test,如果能夠包成helper methods,在不同檔案間重複利用,是再好不過的事情。以下提供兩個簡便的方法,可以撰寫專門給RSpec使用的methods,不會被Rails app本身觸發到。 1. 定義為Module 最快也最簡便的方法,就是在rails_helper.rb或spec_helper.rb裡面定義這些methods,這樣就不用在每一個RSpec檔案當中重新載入(畢竟每次都要require 'rails_helper'就已經夠煩了)。 例如要測試model之間的關係,我們會在測試當中這樣寫: require 'rails_helper' RSpe.describe User, :type => :model do it "has_many posts" do association = User.

ruby on rails

RSpec-Rails 針對module進行unit test

本文概要:在RSpec describe中載入module必須寫成MyClass.new { include MyModule } 若使用RSpec(v3.2)對Rails進行測試,不免俗要針對各種module進行unit test,尤其是helper、service object、或是各種model及controller當中的concern。不過問題來了,要如何在測試當中載入module?小弟一直以為方式是一樣的,但殊不知,在這裡也卡關許久。 rspec-rails這個gem library針對helper module有提供非常簡便的載入方法,我們的測試會寫成這樣: require 'rails_helper' RSpec.describe AppHelper, :type => :helper do # 測試內容 end 可以注意到:type => :helper這個敘述,等於直接載入了helper的內容,我們無需再另外考慮其他因素。 不過這裡有個陷阱,也就是並非所有module都可以這樣載入。如果我們有個service object檔案是greeter.

ruby on rails

模擬class物件:Ruby當中Struct及OpenStruct的使用

為什麼我們需要模擬class物件呢?主要是一個物件有一些屬性需要存取,例如一篇文章Post底下需要title和content兩個屬性,用class來存取就是用牛刀殺雞,太過複雜,用簡單的Hash存取即可。 但Hash其實在某些功能上過於簡單,存取的功能較不方便,假如要模擬的class更為複雜,就需要OpenStruct協助。 OpenStruct OpenStruct跟Hash一樣可以自帶屬性: require 'ostruct' # OpenStruct class不包含在原本Core物件當中,因此需要先require book = OpenStruct.new(title: "Harry Potter", episodes: 7) # 讀取 book.title # => "Harry Potter" book[:title] # => "Harry Potter" book["title"] # => "

ruby on rails

require、require_relative是什麼意思?差在哪?

雖然Ruby本身已經有非常多的功能,但還是常常在Ruby檔案中看到require 'something',例如要使用JSON.parse就必須先require 'json',如果不require就無法使用這些功能。到底這些在檔案最開頭的玩意兒代表什麼意思呢?如果不require又會怎麼樣? require最常見的意義 Ruby內建有許多library,在執行.rb檔案時就已經包含在程式內,包括常用的File、Date等等三不五時就會出現的class,這些因為大家常用,就直接在開始執行.rb程式時包含在Ruby內。但如果載入Ruby時就把所有libraries都放進去,啟動時間會太久,因此Ruby將許多比較沒那麼常用到的class抽出,需另外require。很常見的例子是require 'digest',是一個專門產生亂數、轉碼的工具: Digest::SHA256.hexdigest("HelloWorld") # => NameError: uninitialized constant Digest require 'digest' Digest::SHA256.he

ruby on rails

Rails修改預設顯示格式為json

在Rails當中撰寫controller時,一般都是用respond_to來調整輸出的格式,讓使用者可以自由選擇。例如常見的一般html及json兩種格式: respond_to do |format| format.html { redirect_to @post } format.json { render :show, status: :ok, location: @post } end 這樣不管是連結到html頁面,或是指定輸出為json格式,都可以輕鬆應付。 不過有時我們希望整個controller都是輸出成json格式,不需要html,則可以用幾種方式處理: 1. 直接輸出json格式 一般來說要指定輸出json,都必須在網址列上輸入https://example.com/posts.json,在結尾加上json才會有json格式出現。 如果要強制html輸出成json格式的話,只要在controller action結尾撰寫如下: render :json => @posts 就會將@posts輸出成json格式。 2. 指

ruby on rails

將Rails佈署(Deploy)到VPS上

一般來說,Rails佈署是非常麻煩的事情,尤其整個技術的變遷實在太過快速,很多網路上的資料都舊了。自己最近在研究佈署,發現很多資料都已經過期,在這邊彙整自己將Rails佈署到VPS上的心得。以下示範的是非常精簡的版本,沒有效能調教、沒有安全措施,基本上就只是個能動、稍微對Ruby增加一點彈性的佈署結果。如果有需要更深入的佈署,網路上有非常多關於主機調教的教材。 本機環境:Mac OSX 10.9 Capistrano版本:3.4.0 VPS主機:Digital Ocean 遠端主機作業系統:Ubuntu 14.04 遠端Ruby版本:2.2.0 遠端Rails版本:4.1.2 遠端資料庫:mysql Web Server:nginx App Server:passenger 0.登入VPS 首先,在Digital

ruby on rails

Debugging Rails:了解9個常見的錯誤訊息

身為一個開發者,與bug對抗根本是每天必備功課,而Rails也有非常完備的除錯(debug)方式可供使用。包括幾個強而有力的gem:better_errors、debugger、pry等等。 不過!在使用這些強大的debug工具之前,是否有遇過根本連錯誤訊息都看不懂的情況呢?筆者自己剛開始開發Rails時有些錯誤訊息還要先上google去查才能得到解答。在這裡整理了9個常見到的錯誤以及可能原因,假如大家都能熟悉這些錯誤,以後遇到bug時就可以準確的知道錯誤出在哪裡囉! 1. NoMethodError: undefined method method是Ruby當中所有利用def...end定義的方法都叫method,這段錯誤訊息的意思是你呼叫了一個method,卻沒有定義這個method。通常是由幾個原因造成的: (1)打錯字 最常出現的狀況是例如我們要把user的名字輸出到view當中,卻在view當中指定錯名稱。例如: # controller @user = User.find(params[:id]) View檔案中寫: <%= @user.namm

ruby on rails

Debugging Rails 使用 better_errors 在瀏覽器中直接進行除錯

上一篇提到在發生錯誤時,要先學會閱讀錯誤訊息。但假如無法一時之間了解發生什麼事,那最好有一個可以操作的平台,讓我們了解現在網頁上的variable及method執行起來是什麼情況。 bettererrors這個gem就是針對Rails在產生錯誤訊息時,提供開發者非常完整的資訊來看看錯誤是發生在哪裡。另外搭配bindingof_caller,可以顯示錯誤發生當下的variable列表。 安裝 在Gemfile中列出以下gem: group :development, :test do gem 'better_errors' gem 'binding_of_caller' end 並在command line 中執行bundle進行安裝。 之後再遇到錯誤畫面,會變成以下樣貌: 1. 檢查 stack trace 找到自己的檔案 首先,左邊是一整串檔案列表,跟先前提到的邏輯相同,是整個Rails的檔案列表。進階開發者可以查看整個邏輯,方便debug,初階開發者建議點選左邊的Application Frames並找到自己輸入的檔案即可,因為90%的