MySQL + MySQLWorkbench

這是更換資料庫到 MySQL 的筆記。

這一次能夠解決靠的是官方的 FAQ,而不是 stackoverflow,總之就是我在安裝 MySQL 的時候沒有立即設定密碼所導致的權限 issue,我安裝的方法是透過終端機執行 brew install mysql 並搭配 gem gem mysql 2,同時修改 /config/database.yml 如下:

development:
  adapter: mysql2
  encoding: utf8
  reconnect: false
  database: my_app_development
  pool: 5
  username: root
  password: ooxx

test:
  adapter: mysql2
  encoding: utf8
  reconnect: false
  database: my_app_test
  pool: 5
  username: root
  password: ooxx

production:
  adapter: mysql2
  encoding: utf8
  reconnect: false
  database: my_app_production
  pool: 5

這就是我出問題當下的環境配置。

至於解決的方法是參考 MySQL 官網說明,照做即可。

Devise + Rolify + Cancan

這一篇記錄了搭建管理「使用者後台」遇到的問題。


原本想使用 rails_admin 這個 gem,不過考慮到後期的彈性太小,決定放棄現成的後台 gem,自己手刻,找了一些資料後,看起來最適合的方案就是 Devise + Rolify + Cancan,devise 負責 authentification(user),cancan 負責 authorization(role),rolify 則是讓 devise 方便增加 role。

這裡先列出所有的參考資料

使用Devise+Rolify + Cancan 控管權限
這一篇主要參考了底下這五篇

而這三個 gem 搭配的實作可以參考這篇 rolify 自己提供的 tutorial

在這一份 tutorial 裡有遇到兩個小問題:

  1. Installation -> Run Migrations 出現錯誤,這是 known issue,請參考 解答
  2. 用 rolify 可以 apply role 到需要被卡權限的 model 上,比如說 Post model,但是如果像我一樣要做的是「管理使用者」的後台的話呢?當然就是卡在 User model 上,不過這邊要注意的是在 User model 裡掛 resourcify 上去的時候,必須要擺在 rolify 已經在 User model 寫好的 rolify 之前,否則會報錯,這是因為 rolify 的這兩行 code 在做的事情其實是在拉 association,大家都知道 migration 的 has_many 這些東西是必須要有先後順序的,詳細說明可以看 這裡

接下來開始做後台。

[30 Coder, 120] Tealeaf Course 3 Week 1(6)

這一篇要做的是『顯示最新的六部影片』。這個功能取名做recent_videos,會擺在category裡面當成一種Category的method(這個說法是錯的,不過錯歸錯,卻讓我釐清了一些觀念,很值得說明,特別留下來這個錯誤的說法並在後面說明)來使用,如果影片不到六部,就全部顯示,如果超過六部,就顯示最新的六部。

先從我的做法開始

同樣的先從測試開始,先寫出敘述:

it "should return all videos if less than 6 videos"
it "should return the first 6 most recent videos ordered reverse chronologically"

跑測試,pending。

接著從第一個測試開始:

@category_spec.rb

  • 建立影片,小於六部即可
videos = Video.create([{title: "1", description: "1"}, {title: "2", description: "2"}, {title: "3", description: "3"}, {title: "4", description: "4"}])
  • Category.recent_videos叫出影片,再直接和Video.all相比,並預期會找到相同的影片
expect(Category.recent_videos).to eq(videos)
  • 一如預期的失敗,因為還沒寫recent_videos
NoMethodError:
       undefined method `recent_videos' for #<Class:0x00000102c893c8>

@category.rb

  • 加一個空的method
def self.recent_videos
end
  • test失敗,因為用空的method

  • 如果影片總數小於六部,就全部顯示,所以直接寫限制條件下的Category.recent_videos就是Video.all

def self.recent_videos
  if Video.all.size < 7
    Video.all
  end
end
  • test pass。

接著處理當影片總數超過六部時,recent_videos只找最新的六部,並且從新到舊排列,換句話說,recent_videos的第一部就是Video.all的最後一部,recent_videos的最後一部就是Video.all的倒數第六部,我用第二句話當測試條件

@category_spec.rb

  • recent_videos的最後一部是Video.all的倒數第六部
it "should return the first 6 most recent videos ordered reverse chronologically" do
  videos = Video.create([{title: "1", description: "1"}, {title: "2", description: "2"}, {title: "3", description: "3"}, {title: "4", description: "4"}, {title: "5", description: "5"}, {title: "6", description: "6"}, {title: "7", description: "7"}])
  expect(Category.recent_videos.last).to eq(videos.last(6).first)
end
  • test fail,現在想辦法讓測試通過

@caetgory.rb

  • recent_videos只找最新的六部,並且從新到舊排列
def self.recent_videos
  if Video.all.size < 7
    Video.all
  else
    Video.order(:created_at).reverse.first(6)
  end
end
  • test pass。

看起來應該沒問題了,最後把那個很礙眼的邏輯判斷Video.all.size < 7拉出來另外寫,比較好維護

  • 當影片總數小於七部
def self.is_video_less_than_7?
  Video.all.size < 7
end

這是我的解法,接下來看解答要怎麼痛電我。


首先,我的條件列的太...粗糙了,都有兩個以上的邏輯在,比如說『從新到舊』的『六支影片』,這個就應該拆成兩個測試,另外邊際條件也少考慮一個,就是『沒有影片』,回頭想想,其實我在寫最後一個測試的時候就有這種跡象了:

接著處理當影片總數超過六部時,recent_videos只找最新的六部,並且從新到舊排列,換句話說,recent_videos的第一部就是Video.all的最後一部,recent_videos的最後一部就是Video.all的倒數第六部,我用第二句話當測試條件

如果我一開始就把『從新到舊』拆出來測試,應該就可以測掉第一個條件,所以以後如果出現這種『一個測試很多條件』的時候就該提醒自己邏輯可能拆的不夠細了。

再來,我的model裡也存在著邏輯判斷,這似乎也是很糟糕的一件事。

總的來說以後我要注意幾件事:

  1. model裡存在邏輯
  2. 測試出現選項
  3. 邊際條件(ex: 沒有影片存在)

(7/14 update)
找到一系列文章 介紹TDD,第四個準則就是我犯的錯:

  1. 一次只測試一種測試案例,只測試目標物件一種方法
  2. 最小的測試單位
  3. 不與外部(包括檔案、資料庫、網路、服務、物件、類別)直接相依
  4. 不具備邏輯
  5. 測試案例之間相依性為零

所以解答拆的條件如下:

it "returns the videos in the reverse chronical order by created at"
it "returns all the videos if there are less than 6 videos"
it "returns 6 videos if there are more than 6 videos"
it "returns the most recent 6 videos"
it "returns an empty array if the category does not have any videos"

再來要解釋一下為什麼文章一開始留了一個錯誤的說法,因為這間接的讓我重新學了一遍class/instance method的不同。

其實這個錯誤說法的root cause是我「聽錯了」...作業的目的是要找出『每一個』category的『最新影片』,我聽成只要找『最新影片』,這中間的差別就在於,一個會用class method來做,另一個則用instance method。這怎麼說呢?先拿我聽錯的來講好了,如果照我原本的做法,是用recent_videos找出一種category叫做『最新的六部影片」,也就是透過class method recent_videos操作Category這個model找出最新的六部影片,但如果是正確的做法,是要從『每一個』『Category』裡面找出最新的六部影片,那麼就會變成先用Category找出每一種Category包含的影片(這裡已經變成instance,每一部影片都是Category的instance),再從這些instance裡面找出最新的六部電影,這時候用上的recent_videos就變成了instance method。

class method和instance method的不同,我找到這篇blog寫的很清楚,直接貼範例code更是一看就明白:

class Foo
  def self.bar
    puts 'class method'
  end
  
  def baz
    puts 'instance method'
  end
end

Foo.bar # => "class method"
Foo.baz # => NoMethodError: undefined method ‘baz’ for Foo:Class

Foo.new.baz # => instance method
Foo.new.bar # => NoMethodError: undefined method ‘bar’

從字面上來看,class method只作用在class上,instance method只作用在instance上,換句話說,要使用instance method必須要從某個class new一個instance出來才能做用到這個instance上,instance method是不能作用在class上的,反之亦然。

至於什麼時候要用class method,什麼時候要用instance method呢?可以再拿我們剛剛才做完的搜尋和現在要做的recent_video來比較:

當你要『搜尋』,你利用的是Video這個model去找相關的資料
當你要找『每一個category』裡的『最新的六部電影』,這已經是在對Category的instance去做事情了,用的自然是instance method。

所以,我們要來寫recent_videos這個instance method的測試。

instance method的測試寫法如下:

@category_spec.rb

describe "#recent_videos" do
end

再來加入每一個條件的測試

  • it "returns the videos in the reverse chronical order by created at",所以創一個category和兩部影片,其中一部是一天前建而另一部是剛建的,我們預期找出來的結果comedies.recent_videos和預期的結果[south_park, futurama]要相同

@category_spec.rb

describe "#recent_videos" do
  it "returns the videos in the reverse chronical order by created at" do
    comedies = Category.create(name: "comedies")
    futurama = Video.create(title: "Futurama", description: "space travel", category: comedies, created_at: 1.day.ago)
    south_park = Video.create(title: "South Park", description: "crazy kids", category: comedies)
    expect(comedies.recent_videos).to eq([south_park, futurama])
  end
end
  • test fail,缺method
  • 補method,這裡很有趣的一點就是,在category.rb裡面的recent_videos可以直接用videos當作全部的video

@category.rb

def recent_videos
  videos
end

這樣的寫法等同于

def recent_videos
  self.videos
end

這邊的self指的是對自己用instance method,和class命名裡的self不同,簡單的說 defining a method using self makes it a class method, calling a method using self is calling an instance method

這樣測試會錯誤,因為目前的video是照{ order :title }排列,所以我們把排列順序改成照日期反排{ order "created_at DESC" },就可以讓測試通過。

  • it "returns all the videos if there are less than 6 videos",很簡單,只要把前面的多加上.count還有把預期結果改成2就可以了,因為我們原本就會return所有video

@category_spec.rb

it "returns all the videos if there are less than 6 videos" do
  comedies = Category.create(name: "comedies")
  futurama = Video.create(title: "Futurama", description: "space travel", category: comedies, created_at: 1.day.ago)
  south_park = Video.create(title: "South Park", description: "crazy kids", category: comedies)
  expect(comedies.recent_videos.count).to eq(2)
end
  • it "returns 6 videos if there are more than 6 videos",先create 7部電影,再看recent_videos能不能只抓到六部

@category_spec.rb

it "returns 6 videos if there are more than 6 videos" do
  comedies = Category.create(name: "comedies")
  7.times { Video.create(title: "foo", description: "bar", category: comedies) }
  expect(comedies.recent_videos.count).to eq(6)
end
  • test結果抓到7部,因為目前是return全部video,回頭修改model

@category.rb

def recent_videos
  videos.first(6)
end
  • test pass。

  • it "returns the most recent 6 videos" 再更進一步,除了要return六部電影,還得要六部最新的電影,所以在測試裡我們 create 七部電影,其中一部特別早,而預期的搜尋結果不可以包含這一部:

it "returns the most recent 6 videos" do
  comedies = Category.create(name: "comedies")
  6.times { Video.create(title: "foo", description: "bar", category: comedies) }
  futurama = Video.create(title: "Futurama", description: "space travel", category: comedies, created_at: 1.day.ago)
  expect(comedies.recent_videos).not_to include(futurama)
end
  • test pass,因為我們已經照時間排序,取前六部了。

  • it "returns an empty array if the category does not have any videos" 最後一個測項了,要求在category裡面沒有影片的時候回傳空array,這個也不需要修改:

it "returns an empty array if the category does not have any videos" do
  comedies = Category.create(name: "comedies")
  expect(comedies.recent_videos).to eq([])      
end

收工。


[30 Coder(113), Day 331] Next Step
[30 Coder(112), Day 281] 廣告裁判 2 - Rails New Project
[30 Coder(111), Day 281] 廣告裁判 1 - 準備工作
[30 Coder(110), Day 268] Rails Digest 22 - jQury Preview
[30 Coder(109), Day 266] Rails Digest 21 - Facebook Login
[30 Coder(108), Day 265] Rails Digest 20 - Gravatar
[30 Coder(107), Day 265] Rails Digest 19 - Require Creator
[30 Coder(106), Day 261] Rails Digest 18 - Better Slug/Slug Module
[30 Coder(105), Day 260] Rails Digest 17 - Sluggify Post/Category/User
[30 Coder(104), Day 260] Rails Digest 16 - Push to Heroku
[30 Coder(103), Day 259] Rails Digest 15 - Edit/Show User
[30 Coder(102), Day 258] Rails Digest 14 - Register User
[30 Coder(101), Day 257] Rails Digest 13 - Authentication
[30 Coder(100), Day 257] Rails Digest 12 - has_secure_password
[30 Coder(99), Day 256] Rails Digest 11 - Helpers
[30 Coder(98), Day 255] Rails Digest 10 - Associate category
[30 Coder(97), Day 252] Rails Digest 9 - Errors Partial/Create Comment
[30 Coder(96), Day 251] Rails Digest 8 - Category
[30 Coder(95), Day 251] Rails Digest 7 - Set Post/Form Partial
[30 Coder(94), Day 250] Rails Digest 6 - Edit Post
[30 Coder(93), Day 249] Rails Digest 5 - New Post
[30 Coder(92), Day 249] Rails Digest 4 - Resources
[30 Coder(91), Day 248] Rails Digest 3 - Many to Many Association
[30 Coder(90), Day 248] Rails Digest 2 - Push to GitHub
[30 Coder(89), Day 246] Rails Digest 1 - First Models
[30 Coder(88), Day 245] Finished Tealeaf
[30 Coder(87), Day 244] Tea Leaf - Course 2 Week 4 Time Zones
[30 Coder(86), Day 244] Tea Leaf - Course 2 Week 4 Require Creator
[30 Coder(85), Day 244] Tea Leaf - Course 2 Week 4 Simple Roles
[30 Coder(84), Day 242] Tea Leaf - Course 2 Week 4 Voteable Gem
[30 Coder(83), Day 242] Tea Leaf - Course 2 Week 4 Sluggable Module
[30 Coder(82), Day 242] Tea Leaf - Course 2 Week 4 Voteable Module
[30 Coder(81), Day 242] Tea Leaf - Course 2 Week 4 Better Slugs
[30 Coder(80), Day 242] Tea Leaf - Course 2 Week 4 Sluggify Categories/Users
[30 Coder(79), Day 241] Tea Leaf - Course 2 Week 4 Sluggify Posts
[30 Coder(78), Day 240] Tea Leaf - Course 2 Week 4 Ajaxify Comment Votes
[30 Coder(77), Day 240] Tea Leaf - Course 2 Week 4 Ajaxify Post Votes
[30 Coder(76), Day 239] Ruby on Rails新手村
[30 Coder(75), Day 238] Tea Leaf - Course 2 Week 3 Vote Validation/Deploy to Heroku
[30 Coder(74), Day 238] Tea Leaf - Course 2 Week 3 Comment Vote
[30 Coder(73), Day 237] Tea Leaf - Course 2 Week 3 Post Votes-2
[30 Coder(72), Day 236] Tea Leaf - Course 2 Week 3 Post Votes-1
[30 Coder(71), Day 235] Tea Leaf - Course 2 Week 3 Polymorphic Vote
[30 Coder(70), Day 235] Tea Leaf - Course 2 Week 3 Edit/Show User
[30 Coder(69), Day 231] Tea Leaf - Course 2 Week 3 Authenticate/Register
[30 Coder(68), Day 225] Tea Leaf - Course 2 Week 2 - Form, Review
[30 Coder(67), Day 224] Tea Leaf - Course 2 Week 2 - Form, done
[30 Coder(66), Day 222] Tea Leaf - Course 2 Week 2 - Form
[30 Coder(65), Day 219] Tea Leaf - Course 2 Week 1 - Quiz 1 by classmate
[30 Coder(64), Day 219] Tea Leaf - Course 2 Week 1 - Quiz 1
[30 Coder(63), Day 218] Tea Leaf - Course 2 Week 1 - Resources: Post, Finally
[30 Coder(62), Day 217] Tea Leaf - Course 2 Week 1 - Resources: Post, Again
[30 Coder(61), Day 216] Tea Leaf - Course 2 Week 1 - Resources: Posts
[30 Coder(60), Day 216] Tea Leaf - Course 2 Week 1 - Category Model M:M Association
[30 Coder(59), Day 216] Tea Leaf - Course 2 Week 1 - Comment Model Association
[30 Coder(58), Day 215] Tea Leaf - Course 2 Week 1
[30 Coder(57), Day 215] Tea Leaf - Getting Started with Rails (on hold)
[30 Coder(56), Day 211] Tea Leaf - Getting Started with Rails
[30 Coder(55), Day 209] Tea Leaf - Reading Assignment: Relational Database
[30 Coder(54), Day 208] Tea Leaf - Ruby Exceptions and Exception Handling
[30 Coder(53), Day 205] Tea Leaf - Blackjack Web Version 8/8
[30 Coder(52), Day 203] Tea Leaf - Blackjack Web Version 7/8
[30 Coder(51), Day 201] Tea Leaf - Blackjack Web Version 6/6
[30 Coder(50), Day 201] Tea Leaf - Blackjack Web Version 5/6
[30 Coder(49), Day 201] Tea Leaf - Blackjack Web Version 4/6
[30 Coder(48), Day 200] Tea Leaf - Blackjack Web Version 3/6
[30 Coder(47), Day 198] Tea Leaf - Blackjack Web Version 2/6
[30 Coder(46), Day 198] Tea Leaf - Blackjack Web Version 1/6
[30 Coder(45), Day 198] Tea Leaf - Sinatra
[30 Coder(44), Day 196] Tea Leaf - Back to HTML/CSS
[30 Coder(43), Day 195] Tea Leaf - Object Oriented Blackjack
[30 Coder(42), Day 191] Tea Leaf - Week 2 Note 1
[30 Coder(41), Day 190] Tea Leaf - Oriented Object Programming
[30 Coder(40), Day 189] Tea Leaf - Week 1 Quiz
[30 Coder(39), Day 188] Tea Leaf - Learn to Program Ch11-15
[30 Coder(38), Day 185] Tea Leaf - Learn to Program Ch10
[30 Coder(37), Day 184] Tea Leaf - Ruby Style Guide
[30 Coder(36), Day 183] Tea Leaf - Blackjack
[30 Coder(35), Day 182] Tea Leaf - Ruby Style Guide
[30 Coder(34), Day 181] Tea Leaf - The First Class
[30 Coder(33), Day 178] Tea Leaf - Ruby Exercise
[30 Coder(32), Day 177] Tea Leaf Pre-course 1 Re-read Learn to Program
[30 Coder(31), Day 175] Tea Leaf Pre-course 1 Conclusion
[30 Coder(30), Day 174] Tea Leaf Pre-course of Course 1 - Learn to Program ch 9
[30 Coder(29), Day 171] Tea Leaf Pre-course of Course 1 - Learn to Program ch 8
[30 Coder(28), Day 170] Tea Leaf Pre-course of Course 1 - Learn to Program ch 1-7
[30 Coder(27), Day 169] Tea Leaf Pre-course of Course 1 - Learn to Program
[30 Coder(26), Day 168] Tea Leaf Pre-course of Course 1 - Command Line
[30 Coder(25), Day 167] Tea Leaf Pre-course of Course 1
[30 Coder(24), Day 164] I am all-in
[30 Coder(23), Day 159] It is Ruby on Rails
[30 Coder(22), Day 152] One Month Rails Finish
[30 Coder(21), Day 140] More Rails
[30 Coder(20), Day 130] Rails
[30 Coder(19), Day 122] Ruby
[30 Coder(18), Day 108] GitHub
[30 Coder(17), Day 101] End of Front-end
[30 Coder(16), Day 81] 盤點整理
[30 Coder(15), Day 70] JavaScript, AJAX, Apache
[30 Coder(14), Day 70] JavaScript, Movebox
[30 Coder(13), Day 51] JavaScript, 事件觸發
[30 Coder(12), Day 49] JavaScript, 判斷兩條線是否平行
[30 Coder(11), Day 46] JavaScript, 判斷質數
[30 Coder(10), Day 44] JavaScript
[30 Coder(9), Day 40] CSS定位
[30 Coder(8), Day 37] CSS
[30 Coder(7), Day 30] HTML
[30 Coder(6), Day 25] 起始狀態!
[30 Coder(5), Day 24] 成為你自己的技術創辦人(四)建立原型不可不知六件事
[30 Coder(4), Day 22] 成為你自己的技術創辦人(三)僱個工程師還是DIY?
[30 Coder(3), Day 15] 成為你自己的技術創辦人(二)找不到, 自己來
[30 Coder(2), Day 8] 成為你自己的技術創辦人(一)尋找技術合夥人指南
[30 Coder(1), Day 1] Every Startup Has A Beginning

[30 Coder, 119] Tealeaf Course 3 Week 1(5)

這一篇要來把剛做好的搜尋功能擺進UI。

search的作用是讓使用者輸入字串,送出讓系統查詢,所以可以理解成『送出』一個form,而『送出』也就是POST這個HTTP verb。之前我們在『新增post』這一篇曾經用過model-backed form,不過這一次要做的搜尋功能不需要和model綁定,所以用不到form_for,用form_tag就可以,讓我們從routes開始:

由於不是model-backed form,自然routes也不需要用到resources,只需要另建一個URL/videos/search就可以,而連到這個URL的是POST action,還有搭配的controller及action。

resources :videos, only: [:show, :index] do
  collection do
    post :search, to: "videos#search"
  end
end

這裡我們用的是collection,建出一個在videos底下的path /videos/search,用POST送出到videos controllersearch action

所以接著建search action

def search
  @results = Video.search_by_title(params[:search_term])
end

這裡用到了在上一篇寫好的search_by_title,傳進去的params就叫他作params[:search_term],換句話說我們待會要從form裏面丟一個帶著search_term記號的東西出來,先記著。

再來就是form

= form_tag search_videos_path, class: "col-md-5" do
  %input(name="search_term" type="text" placeholder="Search for videos here")
  %button(type="submit") Search
  • search_videos_path是path helper,跟著剛寫的routes一起產生,忘了的話可以用rake routes
  • 後面的class可以不加,要加的話就這樣寫
  • input欄位要帶上name="search_term",這是剛才說的為了要滿足params[:search_term]用的

這樣去查的話會跑template missing,因為還沒做。

由於是videos#search,所以view當然是建在videos/search.html.haml

- @results.each do |video|
  .video.col-sm-2
    = link_to video do
      %img(src="#{video.small_cover_url}")

很簡單,就是把@result給iterate出來,貼上小圖,輕鬆收工。

收工?收工個鬼啊!Kevin老濕,可以請你不要在我把解答都看完之後說要改解法好嗎?

總之,POST是錯的,Rails說一定要用GET,原因在這邊:

Always use "GET" as the method for search forms. This allows users to bookmark a specific search and get back to it. More generally Rails encourages you to use the right HTTP verb for an action.

改就改,請參考Rails有關form helper以及text_field_tag的官方文件,我的做法如下:

@routes

resources :videos, only: [:show, :index] do
  collection do
    get :search, to: "videos#search"
  end
end
  • POST改成GET

@form

= form_tag search_videos_path, method: "get", class: "col-md-5 navbar-form for-search" do
  = text_field_tag "search_term", nil, placeholder: "Search for videos here", class: "form-control"
  = submit_tag "Search", class: "btn btn-default"
  • form_tag的method改成get
  • 用form helper text_field_tag 取代inputsubmit_tag取代button,重點就是HTML裡的input一定得要有name="search_term"

這次真的收工了。


[30 Coder(113), Day 331] Next Step
[30 Coder(112), Day 281] 廣告裁判 2 - Rails New Project
[30 Coder(111), Day 281] 廣告裁判 1 - 準備工作
[30 Coder(110), Day 268] Rails Digest 22 - jQury Preview
[30 Coder(109), Day 266] Rails Digest 21 - Facebook Login
[30 Coder(108), Day 265] Rails Digest 20 - Gravatar
[30 Coder(107), Day 265] Rails Digest 19 - Require Creator
[30 Coder(106), Day 261] Rails Digest 18 - Better Slug/Slug Module
[30 Coder(105), Day 260] Rails Digest 17 - Sluggify Post/Category/User
[30 Coder(104), Day 260] Rails Digest 16 - Push to Heroku
[30 Coder(103), Day 259] Rails Digest 15 - Edit/Show User
[30 Coder(102), Day 258] Rails Digest 14 - Register User
[30 Coder(101), Day 257] Rails Digest 13 - Authentication
[30 Coder(100), Day 257] Rails Digest 12 - has_secure_password
[30 Coder(99), Day 256] Rails Digest 11 - Helpers
[30 Coder(98), Day 255] Rails Digest 10 - Associate category
[30 Coder(97), Day 252] Rails Digest 9 - Errors Partial/Create Comment
[30 Coder(96), Day 251] Rails Digest 8 - Category
[30 Coder(95), Day 251] Rails Digest 7 - Set Post/Form Partial
[30 Coder(94), Day 250] Rails Digest 6 - Edit Post
[30 Coder(93), Day 249] Rails Digest 5 - New Post
[30 Coder(92), Day 249] Rails Digest 4 - Resources
[30 Coder(91), Day 248] Rails Digest 3 - Many to Many Association
[30 Coder(90), Day 248] Rails Digest 2 - Push to GitHub
[30 Coder(89), Day 246] Rails Digest 1 - First Models
[30 Coder(88), Day 245] Finished Tealeaf
[30 Coder(87), Day 244] Tea Leaf - Course 2 Week 4 Time Zones
[30 Coder(86), Day 244] Tea Leaf - Course 2 Week 4 Require Creator
[30 Coder(85), Day 244] Tea Leaf - Course 2 Week 4 Simple Roles
[30 Coder(84), Day 242] Tea Leaf - Course 2 Week 4 Voteable Gem
[30 Coder(83), Day 242] Tea Leaf - Course 2 Week 4 Sluggable Module
[30 Coder(82), Day 242] Tea Leaf - Course 2 Week 4 Voteable Module
[30 Coder(81), Day 242] Tea Leaf - Course 2 Week 4 Better Slugs
[30 Coder(80), Day 242] Tea Leaf - Course 2 Week 4 Sluggify Categories/Users
[30 Coder(79), Day 241] Tea Leaf - Course 2 Week 4 Sluggify Posts
[30 Coder(78), Day 240] Tea Leaf - Course 2 Week 4 Ajaxify Comment Votes
[30 Coder(77), Day 240] Tea Leaf - Course 2 Week 4 Ajaxify Post Votes
[30 Coder(76), Day 239] Ruby on Rails新手村
[30 Coder(75), Day 238] Tea Leaf - Course 2 Week 3 Vote Validation/Deploy to Heroku
[30 Coder(74), Day 238] Tea Leaf - Course 2 Week 3 Comment Vote
[30 Coder(73), Day 237] Tea Leaf - Course 2 Week 3 Post Votes-2
[30 Coder(72), Day 236] Tea Leaf - Course 2 Week 3 Post Votes-1
[30 Coder(71), Day 235] Tea Leaf - Course 2 Week 3 Polymorphic Vote
[30 Coder(70), Day 235] Tea Leaf - Course 2 Week 3 Edit/Show User
[30 Coder(69), Day 231] Tea Leaf - Course 2 Week 3 Authenticate/Register
[30 Coder(68), Day 225] Tea Leaf - Course 2 Week 2 - Form, Review
[30 Coder(67), Day 224] Tea Leaf - Course 2 Week 2 - Form, done
[30 Coder(66), Day 222] Tea Leaf - Course 2 Week 2 - Form
[30 Coder(65), Day 219] Tea Leaf - Course 2 Week 1 - Quiz 1 by classmate
[30 Coder(64), Day 219] Tea Leaf - Course 2 Week 1 - Quiz 1
[30 Coder(63), Day 218] Tea Leaf - Course 2 Week 1 - Resources: Post, Finally
[30 Coder(62), Day 217] Tea Leaf - Course 2 Week 1 - Resources: Post, Again
[30 Coder(61), Day 216] Tea Leaf - Course 2 Week 1 - Resources: Posts
[30 Coder(60), Day 216] Tea Leaf - Course 2 Week 1 - Category Model M:M Association
[30 Coder(59), Day 216] Tea Leaf - Course 2 Week 1 - Comment Model Association
[30 Coder(58), Day 215] Tea Leaf - Course 2 Week 1
[30 Coder(57), Day 215] Tea Leaf - Getting Started with Rails (on hold)
[30 Coder(56), Day 211] Tea Leaf - Getting Started with Rails
[30 Coder(55), Day 209] Tea Leaf - Reading Assignment: Relational Database
[30 Coder(54), Day 208] Tea Leaf - Ruby Exceptions and Exception Handling
[30 Coder(53), Day 205] Tea Leaf - Blackjack Web Version 8/8
[30 Coder(52), Day 203] Tea Leaf - Blackjack Web Version 7/8
[30 Coder(51), Day 201] Tea Leaf - Blackjack Web Version 6/6
[30 Coder(50), Day 201] Tea Leaf - Blackjack Web Version 5/6
[30 Coder(49), Day 201] Tea Leaf - Blackjack Web Version 4/6
[30 Coder(48), Day 200] Tea Leaf - Blackjack Web Version 3/6
[30 Coder(47), Day 198] Tea Leaf - Blackjack Web Version 2/6
[30 Coder(46), Day 198] Tea Leaf - Blackjack Web Version 1/6
[30 Coder(45), Day 198] Tea Leaf - Sinatra
[30 Coder(44), Day 196] Tea Leaf - Back to HTML/CSS
[30 Coder(43), Day 195] Tea Leaf - Object Oriented Blackjack
[30 Coder(42), Day 191] Tea Leaf - Week 2 Note 1
[30 Coder(41), Day 190] Tea Leaf - Oriented Object Programming
[30 Coder(40), Day 189] Tea Leaf - Week 1 Quiz
[30 Coder(39), Day 188] Tea Leaf - Learn to Program Ch11-15
[30 Coder(38), Day 185] Tea Leaf - Learn to Program Ch10
[30 Coder(37), Day 184] Tea Leaf - Ruby Style Guide
[30 Coder(36), Day 183] Tea Leaf - Blackjack
[30 Coder(35), Day 182] Tea Leaf - Ruby Style Guide
[30 Coder(34), Day 181] Tea Leaf - The First Class
[30 Coder(33), Day 178] Tea Leaf - Ruby Exercise
[30 Coder(32), Day 177] Tea Leaf Pre-course 1 Re-read Learn to Program
[30 Coder(31), Day 175] Tea Leaf Pre-course 1 Conclusion
[30 Coder(30), Day 174] Tea Leaf Pre-course of Course 1 - Learn to Program ch 9
[30 Coder(29), Day 171] Tea Leaf Pre-course of Course 1 - Learn to Program ch 8
[30 Coder(28), Day 170] Tea Leaf Pre-course of Course 1 - Learn to Program ch 1-7
[30 Coder(27), Day 169] Tea Leaf Pre-course of Course 1 - Learn to Program
[30 Coder(26), Day 168] Tea Leaf Pre-course of Course 1 - Command Line
[30 Coder(25), Day 167] Tea Leaf Pre-course of Course 1
[30 Coder(24), Day 164] I am all-in
[30 Coder(23), Day 159] It is Ruby on Rails
[30 Coder(22), Day 152] One Month Rails Finish
[30 Coder(21), Day 140] More Rails
[30 Coder(20), Day 130] Rails
[30 Coder(19), Day 122] Ruby
[30 Coder(18), Day 108] GitHub
[30 Coder(17), Day 101] End of Front-end
[30 Coder(16), Day 81] 盤點整理
[30 Coder(15), Day 70] JavaScript, AJAX, Apache
[30 Coder(14), Day 70] JavaScript, Movebox
[30 Coder(13), Day 51] JavaScript, 事件觸發
[30 Coder(12), Day 49] JavaScript, 判斷兩條線是否平行
[30 Coder(11), Day 46] JavaScript, 判斷質數
[30 Coder(10), Day 44] JavaScript
[30 Coder(9), Day 40] CSS定位
[30 Coder(8), Day 37] CSS
[30 Coder(7), Day 30] HTML
[30 Coder(6), Day 25] 起始狀態!
[30 Coder(5), Day 24] 成為你自己的技術創辦人(四)建立原型不可不知六件事
[30 Coder(4), Day 22] 成為你自己的技術創辦人(三)僱個工程師還是DIY?
[30 Coder(3), Day 15] 成為你自己的技術創辦人(二)找不到, 自己來
[30 Coder(2), Day 8] 成為你自己的技術創辦人(一)尋找技術合夥人指南
[30 Coder(1), Day 1] Every Startup Has A Beginning

[30 Coder, 118] Tealeaf Course 3 Week 1(4)

到目前為止,我只做了一次code review(pull request),然後就切到目前這個branch,理論上應該是要再pull request回去一次讓助教幫忙看一下進度,不過老師也講了,如果你最後都是照著solution做,其實也可以不用code review,所以我決定直接merge回我的master brance,這裡簡單的做個merge的筆記:

  • 先切換到你目前的feature branch:git checkout test-category-model-and-association
  • git add .git commitgit push
  • 接著切回master branch:git checkout master,因為要merge的話branch要在你的目的地,也就是master
  • 然後把你要merge的branch merge進來:git merge test-category-model-and-association
  • 接著再git add .git commitgit push

收工。

[30 Coder, 117] Tealeaf Course 3 Week 1(3)

接下來是下半場的lesson筆記。

另外值得一提的是,社群朋友聽到我剛開始學測試,立刻介紹了一個Sublime Text的外掛,可以直接在Sublime裡跑rspec,不需要特地切到terminal去執行,省了非常多時間,這個外掛叫做"sublime-text-2-ruby-tests",有在用Sublime的可以參考。

  • blank is either nil or empty string

Member Routes and Collection Routes

這一個assignment要做的是搜尋,第一個note是筆記,第二個membercollection的比較是因為搜尋的routes會用到。

首先搜尋的method會做到model裡,不過在真正實作搜尋功能之前,我們先做測試,所以先讓我們列出來『搜尋』這個功能所有可能遇到的狀況:

  1. 找不到結果,return一個空的array
  2. 找到『一部』『完全命中』的影片,return一個array
  3. 找到『一部』『部分命中』的影片,return一個array
  4. 找到『很多』『命中』的影片,return一個array,並依照created_at做排序
    • 當return array裡有很多東西時永遠記得要考慮order

所以先列出所有可能的測試情況

describe "search_by_title" do
  it "returns an empty array if there is no match"
  it "returns an array of one video for an exact match"
  it "returns an array of one video for a partial match"
  it "returns an array of all matched ordered by created_at"
end
  1. 從第一個測試開始寫:

    • 先create兩個video,再丟一個string hello,用search_by_title這個method去搜尋,預期會得到一個空的array
      it "returns an empty array if there is no match" do
      futurama = Video.create(title: "Futurama", description: "Gotham needs a hero.")
      back_to_future = Video.create(title: "Back to Future", description: "Gotham needs a hero.")
      expect(Video.search_by_title("hello")).to eq([])
      end
      
    • 接著跑rspec,會fail,因為我們還沒做search_by_title,立馬補到video model:
      def self.search_by_title
      end
      
    • 呃,空的?對,沒錯,就是要空的,因為TDD的一個很重要的思考邏輯是所謂的"red-green-refactor",先求測試失敗,再寫出可以過的程式碼,剛才我們的rspec fail單純只是因為沒有search_by_title這個method,所以我們現在補上,讓rspec可以『正常的fail』,不過這樣還是會『不正常的fail』,因為我們在test裡有丟一個string hello,但是method裡面沒有,所以rspec會出一個錯誤叫做wrong number of arguments (1 for 0),所以再補上
      def self.search_by_title(search_term)
      end
      
    • 結果還是不正常的fail,錯誤訊息告訴我們他預期的是一個空的array,卻跑出了nil,這是因為一個空的ruby code永遠會return nil,要改正這個問題也很簡單,丟一個空的array就可以了
      def self.search_by_title(search_term)
      []
      end
      
    • 很好,這一次過關了,可以進到下一個測試
  2. 第二個測試是找到一個完全符合的結果:

    • 所以同樣create一個object futurama並且丟Futurama這個string進去測試,預期可以得到一個包含了object futurama的array
      it "returns an array of one video for an exact match" do
      futurama = Video.create(title: "Futurama", description: "Gotham needs a hero.")
      back_to_future = Video.create(title: "Back to Future", description: "Gotham needs a hero.")
      expect(Video.search_by_title("Futurama")).to eq([futurama])
      end
      
    • 失敗。
      expected: #<Video id: 1, title: "Futurama", description: "Gotham needs a hero.", small_cover_url: nil, large_cover_url: nil, created_at: "2014-07-09 07:20:22", updated_at: "2014-07-09 07:20:22", category_id: nil>
      got: []
      
    • 失敗的原因也很簡單,因為預期要得到的objectfuturama沒有出現,反而跑了一個空的array出來(因為是我們寫死的),所以這下要動真格的把搜尋功能做出來了,用的是ActiveRecord裡的where搭配LIKE,有關ActiveRecord可以參考這裡
      def self.search_by_title(search_term)
      where("title LIKE ?", "#{search_term}")
      end
      
    • 我們要search的是titletitleLIKE某個東西,我們用問號?來暫代某個東西,而逗點之後的第二個parameter "#{search_term}"就是這某個東西,也就是真正要用的SQL query,這種寫法叫『prepare statement』。
    • 再跑一次測試就可以pass
  3. 第三個是partial match的測試:

    • 我們改丟一個string uturama去search:
      it "returns an array of one video for a partial match" do
      futurama = Video.create(title: "Futurama", description: "Gotham needs a hero.")
      back_to_future = Video.create(title: "Back to Future", description: "Gotham needs a hero.")
      expect(Video.search_by_title("uturama")).to eq([futurama])
      end
    • test fail,因為目前的SQL還是只會找100% match的結果,要做partial match,還得在頭尾加上%,變成%#{search_term}%
    • test pass。
  4. 最後一個測試需要把完全/partial符合的搜尋結果照created_at排序,這次改丟string Futur,這樣兩部電影都可以被找到:

    • futuramacreated_at定的比另一部電影早,這樣搜尋的結果應該要先找到back_to_future,但因為我們還沒有做任何SQL的更動,出來的順序還是照原本資料的排序:
      it "returns an array of all matched ordered by created_at" do
      futurama = Video.create(title: "Futurama", description: "Gotham needs a hero.", created_at: 1.day.ago)
      back_to_future = Video.create(title: "Back to Future", description: "Gotham needs a hero.")
      expect(Video.search_by_title("Futur")).to eq([back_to_future, futurama])
      end
    • 這樣測試的結果當然是fail,因此修改如下:
      def self.search_by_title(search_term)
      where("title LIKE ?", "%#{search_term}%").order("created_at DESC")
      end
      
    • test pass。
  5. 最後要來考慮一個例外,就是當使用者搜尋一個空字串的時候:

    • 我們不能return資料庫裡的所有東西,而是return一個空array:
      it "returns an empty array for a search with an empty string" do
      futurama = Video.create(title: "Futurama", description: "Gotham needs a hero.", created_at: 1.day.ago)
      back_to_future = Video.create(title: "Back to Future", description: "Gotham needs a hero.")
      expect(Video.search_by_title("")).to eq([])
      end
      
    • test fail,修補的方法也很簡單,就是指名在搜尋空字串的時候要return一個空array
      def self.search_by_title(search_term)
      return [] if search_term.blank?
      where("title LIKE ?", "%#{search_term}%").order("created_at DESC")
      end
      
    • test pass,打完收工

[30 Coder(113), Day 331] Next Step
[30 Coder(112), Day 281] 廣告裁判 2 - Rails New Project
[30 Coder(111), Day 281] 廣告裁判 1 - 準備工作
[30 Coder(110), Day 268] Rails Digest 22 - jQury Preview
[30 Coder(109), Day 266] Rails Digest 21 - Facebook Login
[30 Coder(108), Day 265] Rails Digest 20 - Gravatar
[30 Coder(107), Day 265] Rails Digest 19 - Require Creator
[30 Coder(106), Day 261] Rails Digest 18 - Better Slug/Slug Module
[30 Coder(105), Day 260] Rails Digest 17 - Sluggify Post/Category/User
[30 Coder(104), Day 260] Rails Digest 16 - Push to Heroku
[30 Coder(103), Day 259] Rails Digest 15 - Edit/Show User
[30 Coder(102), Day 258] Rails Digest 14 - Register User
[30 Coder(101), Day 257] Rails Digest 13 - Authentication
[30 Coder(100), Day 257] Rails Digest 12 - has_secure_password
[30 Coder(99), Day 256] Rails Digest 11 - Helpers
[30 Coder(98), Day 255] Rails Digest 10 - Associate category
[30 Coder(97), Day 252] Rails Digest 9 - Errors Partial/Create Comment
[30 Coder(96), Day 251] Rails Digest 8 - Category
[30 Coder(95), Day 251] Rails Digest 7 - Set Post/Form Partial
[30 Coder(94), Day 250] Rails Digest 6 - Edit Post
[30 Coder(93), Day 249] Rails Digest 5 - New Post
[30 Coder(92), Day 249] Rails Digest 4 - Resources
[30 Coder(91), Day 248] Rails Digest 3 - Many to Many Association
[30 Coder(90), Day 248] Rails Digest 2 - Push to GitHub
[30 Coder(89), Day 246] Rails Digest 1 - First Models
[30 Coder(88), Day 245] Finished Tealeaf
[30 Coder(87), Day 244] Tea Leaf - Course 2 Week 4 Time Zones
[30 Coder(86), Day 244] Tea Leaf - Course 2 Week 4 Require Creator
[30 Coder(85), Day 244] Tea Leaf - Course 2 Week 4 Simple Roles
[30 Coder(84), Day 242] Tea Leaf - Course 2 Week 4 Voteable Gem
[30 Coder(83), Day 242] Tea Leaf - Course 2 Week 4 Sluggable Module
[30 Coder(82), Day 242] Tea Leaf - Course 2 Week 4 Voteable Module
[30 Coder(81), Day 242] Tea Leaf - Course 2 Week 4 Better Slugs
[30 Coder(80), Day 242] Tea Leaf - Course 2 Week 4 Sluggify Categories/Users
[30 Coder(79), Day 241] Tea Leaf - Course 2 Week 4 Sluggify Posts
[30 Coder(78), Day 240] Tea Leaf - Course 2 Week 4 Ajaxify Comment Votes
[30 Coder(77), Day 240] Tea Leaf - Course 2 Week 4 Ajaxify Post Votes
[30 Coder(76), Day 239] Ruby on Rails新手村
[30 Coder(75), Day 238] Tea Leaf - Course 2 Week 3 Vote Validation/Deploy to Heroku
[30 Coder(74), Day 238] Tea Leaf - Course 2 Week 3 Comment Vote
[30 Coder(73), Day 237] Tea Leaf - Course 2 Week 3 Post Votes-2
[30 Coder(72), Day 236] Tea Leaf - Course 2 Week 3 Post Votes-1
[30 Coder(71), Day 235] Tea Leaf - Course 2 Week 3 Polymorphic Vote
[30 Coder(70), Day 235] Tea Leaf - Course 2 Week 3 Edit/Show User
[30 Coder(69), Day 231] Tea Leaf - Course 2 Week 3 Authenticate/Register
[30 Coder(68), Day 225] Tea Leaf - Course 2 Week 2 - Form, Review
[30 Coder(67), Day 224] Tea Leaf - Course 2 Week 2 - Form, done
[30 Coder(66), Day 222] Tea Leaf - Course 2 Week 2 - Form
[30 Coder(65), Day 219] Tea Leaf - Course 2 Week 1 - Quiz 1 by classmate
[30 Coder(64), Day 219] Tea Leaf - Course 2 Week 1 - Quiz 1
[30 Coder(63), Day 218] Tea Leaf - Course 2 Week 1 - Resources: Post, Finally
[30 Coder(62), Day 217] Tea Leaf - Course 2 Week 1 - Resources: Post, Again
[30 Coder(61), Day 216] Tea Leaf - Course 2 Week 1 - Resources: Posts
[30 Coder(60), Day 216] Tea Leaf - Course 2 Week 1 - Category Model M:M Association
[30 Coder(59), Day 216] Tea Leaf - Course 2 Week 1 - Comment Model Association
[30 Coder(58), Day 215] Tea Leaf - Course 2 Week 1
[30 Coder(57), Day 215] Tea Leaf - Getting Started with Rails (on hold)
[30 Coder(56), Day 211] Tea Leaf - Getting Started with Rails
[30 Coder(55), Day 209] Tea Leaf - Reading Assignment: Relational Database
[30 Coder(54), Day 208] Tea Leaf - Ruby Exceptions and Exception Handling
[30 Coder(53), Day 205] Tea Leaf - Blackjack Web Version 8/8
[30 Coder(52), Day 203] Tea Leaf - Blackjack Web Version 7/8
[30 Coder(51), Day 201] Tea Leaf - Blackjack Web Version 6/6
[30 Coder(50), Day 201] Tea Leaf - Blackjack Web Version 5/6
[30 Coder(49), Day 201] Tea Leaf - Blackjack Web Version 4/6
[30 Coder(48), Day 200] Tea Leaf - Blackjack Web Version 3/6
[30 Coder(47), Day 198] Tea Leaf - Blackjack Web Version 2/6
[30 Coder(46), Day 198] Tea Leaf - Blackjack Web Version 1/6
[30 Coder(45), Day 198] Tea Leaf - Sinatra
[30 Coder(44), Day 196] Tea Leaf - Back to HTML/CSS
[30 Coder(43), Day 195] Tea Leaf - Object Oriented Blackjack
[30 Coder(42), Day 191] Tea Leaf - Week 2 Note 1
[30 Coder(41), Day 190] Tea Leaf - Oriented Object Programming
[30 Coder(40), Day 189] Tea Leaf - Week 1 Quiz
[30 Coder(39), Day 188] Tea Leaf - Learn to Program Ch11-15
[30 Coder(38), Day 185] Tea Leaf - Learn to Program Ch10
[30 Coder(37), Day 184] Tea Leaf - Ruby Style Guide
[30 Coder(36), Day 183] Tea Leaf - Blackjack
[30 Coder(35), Day 182] Tea Leaf - Ruby Style Guide
[30 Coder(34), Day 181] Tea Leaf - The First Class
[30 Coder(33), Day 178] Tea Leaf - Ruby Exercise
[30 Coder(32), Day 177] Tea Leaf Pre-course 1 Re-read Learn to Program
[30 Coder(31), Day 175] Tea Leaf Pre-course 1 Conclusion
[30 Coder(30), Day 174] Tea Leaf Pre-course of Course 1 - Learn to Program ch 9
[30 Coder(29), Day 171] Tea Leaf Pre-course of Course 1 - Learn to Program ch 8
[30 Coder(28), Day 170] Tea Leaf Pre-course of Course 1 - Learn to Program ch 1-7
[30 Coder(27), Day 169] Tea Leaf Pre-course of Course 1 - Learn to Program
[30 Coder(26), Day 168] Tea Leaf Pre-course of Course 1 - Command Line
[30 Coder(25), Day 167] Tea Leaf Pre-course of Course 1
[30 Coder(24), Day 164] I am all-in
[30 Coder(23), Day 159] It is Ruby on Rails
[30 Coder(22), Day 152] One Month Rails Finish
[30 Coder(21), Day 140] More Rails
[30 Coder(20), Day 130] Rails
[30 Coder(19), Day 122] Ruby
[30 Coder(18), Day 108] GitHub
[30 Coder(17), Day 101] End of Front-end
[30 Coder(16), Day 81] 盤點整理
[30 Coder(15), Day 70] JavaScript, AJAX, Apache
[30 Coder(14), Day 70] JavaScript, Movebox
[30 Coder(13), Day 51] JavaScript, 事件觸發
[30 Coder(12), Day 49] JavaScript, 判斷兩條線是否平行
[30 Coder(11), Day 46] JavaScript, 判斷質數
[30 Coder(10), Day 44] JavaScript
[30 Coder(9), Day 40] CSS定位
[30 Coder(8), Day 37] CSS
[30 Coder(7), Day 30] HTML
[30 Coder(6), Day 25] 起始狀態!
[30 Coder(5), Day 24] 成為你自己的技術創辦人(四)建立原型不可不知六件事
[30 Coder(4), Day 22] 成為你自己的技術創辦人(三)僱個工程師還是DIY?
[30 Coder(3), Day 15] 成為你自己的技術創辦人(二)找不到, 自己來
[30 Coder(2), Day 8] 成為你自己的技術創辦人(一)尋找技術合夥人指南
[30 Coder(1), Day 1] Every Startup Has A Beginning

[30 Coder, 116] Tealeaf Course 3 Week 1(2)

前天submit precourse的code有一些feedback,基本上就是我改的太淺了,必須要把video/category的model/controller都翻修過才行,所以這是我更改之後的版本

比較值得一提的是在測試的部分,課堂上講的測試是用Video.last.title.should == "Batman"這樣的語法,解答裡用的則是目前rpsec team比較推薦的寫法expect(Video.last).to eq(video),同樣是非常口語,至於這種寫法的優點請參考rspec team的這篇blog

接下來的作業是測Category model以及CategoryVideo之間的association,這是我的寫法,測試是pass的

require 'spec_helper'

describe Category do
  it "saves itself" do
    category = Category.new(name: "Soap")
    category.save
    expect(Category.last).to eq(category)
  end
end

describe Category do
  it "links video" do
    category = Category.new(name: "Soap")
    video = Video.new(title: "Batman", description: "Gotham needs a hero.")
    video.category = category
    video.save
    category.save
    expect(Category.last.videos.last).to eq(video)
  end
end

至於解答則是用create取代new,好處是不用多一個save的步驟,並多建了一支影片,而且在建立時直接把category寫進去,並且介紹了include這個不考慮順序的檢查方式,而且兩個測試寫在一個describe裡面即可,所以改寫我的做法如下:

require 'spec_helper'

describe Category do
  it "saves itself" do
    category = Category.new(name: "Soap")
    category.save
    expect(Category.last).to eq(category)
  end

  it "has many videos" do
    soaps = Category.create(name: "Soaps")
    batman = Video.create(title: "Batman", description: "Gotham needs a hero.", category: soaps)
    superman = Video.create(title: "Superman", description: "Metropolis needs a hero.", category: soaps)
    expect(soaps.videos).to include(batman, superman)
  end
end

不過一般來說我們還是希望建立資料的時候是有順序性的,所以改寫category model,加上以title排序如下:

class Category < ActiveRecord::Base
  has_many :videos, order: :title
end

請注意:作業解答有錯,在新版的Rails裡,已經不能把activerecord methods使用在associations的scope block之外,所以參照API Dock,應該要改寫成

class Category < ActiveRecord::Base
  has_many :videos, -> { order :title }
end

測試就可以改成

require 'spec_helper'

describe Category do
  it "saves itself" do
    category = Category.new(name: "Soap")
    category.save
    expect(Category.last).to eq(category)
  end

  it "has many videos" do
    soaps = Category.create(name: "Soaps")
    batman = Video.create(title: "Batman", description: "Gotham needs a hero.", category: soaps)
    superman = Video.create(title: "Superman", description: "Metropolis needs a hero.", category: soaps)
    expect(soaps.videos).to eq([batman, superman])
  end
end

請注意eq([batman, superman])中已經改成array。

反過來也測一下video這邊的association:

it "belongs to category" do
  soaps = Category.create(name: "Soaps")
  batman = Video.create(title: "Batman", description: "Gotham needs a hero.", category: soaps)
  expect(batman.category).to eq(soaps)
end

下一個作業是要測試validation,我找到兩個比較有可能的Stackoverflow,其中一個有用到Factory Girl這個gem暫時不考慮,另一個方法可以pass測試(不過rspec提醒我說這個方法已經deprecated了):

it "must have a title" do    
  subject.should have(1).error_on(:title)
end

it "must have a description" do
  subject.should have(1).error_on(:description)
end

這裡利用了rspec一個有趣的特性,就是假如我們測試的是一個class,rspec會自動在每一個測試前做一個instance出來,調用的方法則是透過subject(),而且可以進一步縮寫成:

it { should have(1).error_on(:title) }
it { should have(1).error_on(:description) }

不過既然過期了,就看一下rspec的提示吧:

Deprecation Warnings:

`expect(record).to have(1).error_on(:title)` is deprecated. Use the rspec-collection_matchers gem or replace your expectation with something like 

    record.valid?
    expect(record.errors[:title].size).to eq(1)

 instead. Called from /Users/Mac/GitHub/myflix/spec/models/video_spec.rb:20:in `block (2 levels) in <top (required)>'.
`expect(record).to have(1).error_on(:description)` is deprecated. Use the rspec-collection_matchers gem or replace your expectation with something like 

    record.valid?
    expect(record.errors[:description].size).to eq(1)

 instead. Called from /User

所以就照著改吧:

it "must have a title" do    
    subject.valid?
    expect(subject.errors[:title].size).to eq(1)
end

it "must have a description" do
    subject.valid?
    expect(subject.errors[:description].size).to eq(1)
end

至於在model的部分,我覺得除了validate presence之外還應該對title validate unique,所以我寫成:

class Video < ActiveRecord::Base
  belongs_to :category

  validates :title, presence: true, uniqueness: true
  validates :description, presence: true
end

這樣的測試是可以過的,接著來看看解答的做法:

剛才我找到的做法是檢查error的數量(應該為1),解答則是檢查存進資料庫的Video數量 (應該為0),並且由於題目要求的只有validate presence,所以model的部分寫成:

class Video < ActiveRecord::Base
  belongs_to :category

  validates_presence_of :title, :description
end

而測試則是:

it "does not save a video without a title" do
  video = Video.create(description: "a great movie!")
  expect(Video.count).to eq(0)
end

it "does not save a video without a dexsription" do
  video = Video.create(title: "monk")
  expect(Video.count).to eq(0)
end

不過這一切的一切在引入shoulda_matchers之後就改觀了...非常威猛的一個gem,把很多的測試都簡化了,比如說剛才的validate_presence_of測試可以簡化成

it { should validate_presence_of :title }
it { should validate_presence_of :description }

belongs_to則可以寫成

it { should belong_to :category }

威。猛。無。匹。

Category那邊就不用說了,直接簡化:

it { should have_many :videos }

至於我們一開始寫的儲存的測試其實是多餘的,這是Rails的工作,我們不需要對Rails的function做測試,而是對程式碼做測試。到這邊是week 1的中場休息,下半場另開一篇重新寫過。

[30 Coder(113), Day 331] Next Step
[30 Coder(112), Day 281] 廣告裁判 2 - Rails New Project
[30 Coder(111), Day 281] 廣告裁判 1 - 準備工作
[30 Coder(110), Day 268] Rails Digest 22 - jQury Preview
[30 Coder(109), Day 266] Rails Digest 21 - Facebook Login
[30 Coder(108), Day 265] Rails Digest 20 - Gravatar
[30 Coder(107), Day 265] Rails Digest 19 - Require Creator
[30 Coder(106), Day 261] Rails Digest 18 - Better Slug/Slug Module
[30 Coder(105), Day 260] Rails Digest 17 - Sluggify Post/Category/User
[30 Coder(104), Day 260] Rails Digest 16 - Push to Heroku
[30 Coder(103), Day 259] Rails Digest 15 - Edit/Show User
[30 Coder(102), Day 258] Rails Digest 14 - Register User
[30 Coder(101), Day 257] Rails Digest 13 - Authentication
[30 Coder(100), Day 257] Rails Digest 12 - has_secure_password
[30 Coder(99), Day 256] Rails Digest 11 - Helpers
[30 Coder(98), Day 255] Rails Digest 10 - Associate category
[30 Coder(97), Day 252] Rails Digest 9 - Errors Partial/Create Comment
[30 Coder(96), Day 251] Rails Digest 8 - Category
[30 Coder(95), Day 251] Rails Digest 7 - Set Post/Form Partial
[30 Coder(94), Day 250] Rails Digest 6 - Edit Post
[30 Coder(93), Day 249] Rails Digest 5 - New Post
[30 Coder(92), Day 249] Rails Digest 4 - Resources
[30 Coder(91), Day 248] Rails Digest 3 - Many to Many Association
[30 Coder(90), Day 248] Rails Digest 2 - Push to GitHub
[30 Coder(89), Day 246] Rails Digest 1 - First Models
[30 Coder(88), Day 245] Finished Tealeaf
[30 Coder(87), Day 244] Tea Leaf - Course 2 Week 4 Time Zones
[30 Coder(86), Day 244] Tea Leaf - Course 2 Week 4 Require Creator
[30 Coder(85), Day 244] Tea Leaf - Course 2 Week 4 Simple Roles
[30 Coder(84), Day 242] Tea Leaf - Course 2 Week 4 Voteable Gem
[30 Coder(83), Day 242] Tea Leaf - Course 2 Week 4 Sluggable Module
[30 Coder(82), Day 242] Tea Leaf - Course 2 Week 4 Voteable Module
[30 Coder(81), Day 242] Tea Leaf - Course 2 Week 4 Better Slugs
[30 Coder(80), Day 242] Tea Leaf - Course 2 Week 4 Sluggify Categories/Users
[30 Coder(79), Day 241] Tea Leaf - Course 2 Week 4 Sluggify Posts
[30 Coder(78), Day 240] Tea Leaf - Course 2 Week 4 Ajaxify Comment Votes
[30 Coder(77), Day 240] Tea Leaf - Course 2 Week 4 Ajaxify Post Votes
[30 Coder(76), Day 239] Ruby on Rails新手村
[30 Coder(75), Day 238] Tea Leaf - Course 2 Week 3 Vote Validation/Deploy to Heroku
[30 Coder(74), Day 238] Tea Leaf - Course 2 Week 3 Comment Vote
[30 Coder(73), Day 237] Tea Leaf - Course 2 Week 3 Post Votes-2
[30 Coder(72), Day 236] Tea Leaf - Course 2 Week 3 Post Votes-1
[30 Coder(71), Day 235] Tea Leaf - Course 2 Week 3 Polymorphic Vote
[30 Coder(70), Day 235] Tea Leaf - Course 2 Week 3 Edit/Show User
[30 Coder(69), Day 231] Tea Leaf - Course 2 Week 3 Authenticate/Register
[30 Coder(68), Day 225] Tea Leaf - Course 2 Week 2 - Form, Review
[30 Coder(67), Day 224] Tea Leaf - Course 2 Week 2 - Form, done
[30 Coder(66), Day 222] Tea Leaf - Course 2 Week 2 - Form
[30 Coder(65), Day 219] Tea Leaf - Course 2 Week 1 - Quiz 1 by classmate
[30 Coder(64), Day 219] Tea Leaf - Course 2 Week 1 - Quiz 1
[30 Coder(63), Day 218] Tea Leaf - Course 2 Week 1 - Resources: Post, Finally
[30 Coder(62), Day 217] Tea Leaf - Course 2 Week 1 - Resources: Post, Again
[30 Coder(61), Day 216] Tea Leaf - Course 2 Week 1 - Resources: Posts
[30 Coder(60), Day 216] Tea Leaf - Course 2 Week 1 - Category Model M:M Association
[30 Coder(59), Day 216] Tea Leaf - Course 2 Week 1 - Comment Model Association
[30 Coder(58), Day 215] Tea Leaf - Course 2 Week 1
[30 Coder(57), Day 215] Tea Leaf - Getting Started with Rails (on hold)
[30 Coder(56), Day 211] Tea Leaf - Getting Started with Rails
[30 Coder(55), Day 209] Tea Leaf - Reading Assignment: Relational Database
[30 Coder(54), Day 208] Tea Leaf - Ruby Exceptions and Exception Handling
[30 Coder(53), Day 205] Tea Leaf - Blackjack Web Version 8/8
[30 Coder(52), Day 203] Tea Leaf - Blackjack Web Version 7/8
[30 Coder(51), Day 201] Tea Leaf - Blackjack Web Version 6/6
[30 Coder(50), Day 201] Tea Leaf - Blackjack Web Version 5/6
[30 Coder(49), Day 201] Tea Leaf - Blackjack Web Version 4/6
[30 Coder(48), Day 200] Tea Leaf - Blackjack Web Version 3/6
[30 Coder(47), Day 198] Tea Leaf - Blackjack Web Version 2/6
[30 Coder(46), Day 198] Tea Leaf - Blackjack Web Version 1/6
[30 Coder(45), Day 198] Tea Leaf - Sinatra
[30 Coder(44), Day 196] Tea Leaf - Back to HTML/CSS
[30 Coder(43), Day 195] Tea Leaf - Object Oriented Blackjack
[30 Coder(42), Day 191] Tea Leaf - Week 2 Note 1
[30 Coder(41), Day 190] Tea Leaf - Oriented Object Programming
[30 Coder(40), Day 189] Tea Leaf - Week 1 Quiz
[30 Coder(39), Day 188] Tea Leaf - Learn to Program Ch11-15
[30 Coder(38), Day 185] Tea Leaf - Learn to Program Ch10
[30 Coder(37), Day 184] Tea Leaf - Ruby Style Guide
[30 Coder(36), Day 183] Tea Leaf - Blackjack
[30 Coder(35), Day 182] Tea Leaf - Ruby Style Guide
[30 Coder(34), Day 181] Tea Leaf - The First Class
[30 Coder(33), Day 178] Tea Leaf - Ruby Exercise
[30 Coder(32), Day 177] Tea Leaf Pre-course 1 Re-read Learn to Program
[30 Coder(31), Day 175] Tea Leaf Pre-course 1 Conclusion
[30 Coder(30), Day 174] Tea Leaf Pre-course of Course 1 - Learn to Program ch 9
[30 Coder(29), Day 171] Tea Leaf Pre-course of Course 1 - Learn to Program ch 8
[30 Coder(28), Day 170] Tea Leaf Pre-course of Course 1 - Learn to Program ch 1-7
[30 Coder(27), Day 169] Tea Leaf Pre-course of Course 1 - Learn to Program
[30 Coder(26), Day 168] Tea Leaf Pre-course of Course 1 - Command Line
[30 Coder(25), Day 167] Tea Leaf Pre-course of Course 1
[30 Coder(24), Day 164] I am all-in
[30 Coder(23), Day 159] It is Ruby on Rails
[30 Coder(22), Day 152] One Month Rails Finish
[30 Coder(21), Day 140] More Rails
[30 Coder(20), Day 130] Rails
[30 Coder(19), Day 122] Ruby
[30 Coder(18), Day 108] GitHub
[30 Coder(17), Day 101] End of Front-end
[30 Coder(16), Day 81] 盤點整理
[30 Coder(15), Day 70] JavaScript, AJAX, Apache
[30 Coder(14), Day 70] JavaScript, Movebox
[30 Coder(13), Day 51] JavaScript, 事件觸發
[30 Coder(12), Day 49] JavaScript, 判斷兩條線是否平行
[30 Coder(11), Day 46] JavaScript, 判斷質數
[30 Coder(10), Day 44] JavaScript
[30 Coder(9), Day 40] CSS定位
[30 Coder(8), Day 37] CSS
[30 Coder(7), Day 30] HTML
[30 Coder(6), Day 25] 起始狀態!
[30 Coder(5), Day 24] 成為你自己的技術創辦人(四)建立原型不可不知六件事
[30 Coder(4), Day 22] 成為你自己的技術創辦人(三)僱個工程師還是DIY?
[30 Coder(3), Day 15] 成為你自己的技術創辦人(二)找不到, 自己來
[30 Coder(2), Day 8] 成為你自己的技術創辦人(一)尋找技術合夥人指南
[30 Coder(1), Day 1] Every Startup Has A Beginning

[30 Coder, 115] Tealeaf Course 3 Week 1(1)

  • unit test 測model/helper/view/routes
  • function test 測controller
    • 因為controller裡面可能有很多model,合理

第一個測試
先在gem file加入rspec

group :development, :test do
  gem 'rspec-rails'
end

rails g rspec:install

這時候打開.rspec只會看到--color這一行code,代表的是rspec跑出來的結果會上色。

接下來準備測第一個model。先到spec底下新開一個資料夾models,專門拿來測model。課程中要測的第一個model叫做todo,所以建一個todo_spec.rbspec/models

require 'spec_helper'
 
describe Todo do
end

這時候試跑rspec,記得要回到project主目錄底下輸入rspec
就可以得到一個綠色的測試結果,告訴我們rspec測了0個example, 0個failure,也就是所謂的不寫不錯.

接下來我們要寫第一件待測事項:存檔

require 'spec_helper'
 
describe Todo do
  it "saves itself" do
    todo = Todo.new(name: "cook dinner", description: "I love cooking!")
    todo.save
    Todo.first.name.should == "cook dinner"
  end
end

這個測試很口語的,想像自己是一個洋腔洋調的ABC: descripbr一下Todo這個model,it應該saves itself當我們新建一個object todo = Todo.new(name: "cook dinner", description: "I love cooking!")並且todo.save之後,我們跑rspec去執行Todo.first.name的時候should要跑出== "cook dinner"這個結果

這時候再跑rspec,就可以得到1 example, 0 failures,還附帶一個小綠點,告訴我們有'一個'測試pass了。

再來必須要理解develop和test用的database是不同的,所以在rake db:migrate的時候也需要把測試用的資料庫也拉進來,變成rake db:migrate db:test:prepare,不然你在做測試的時候會誤以為你已經有了某些table,但其實你一無所有

不過在rails 4.1已經很貼心的幫我們做掉db:test:prepare這件事了,所以就當成看歷史吧,不過也別忘了這件事的來龍去脈。

接下來介紹所謂的github flow,這是Github內部基於一套叫做"git-flow"簡化而來的專案流程,這裡就不多做介紹,網路上已經有很多相關資訊,像是ihower就寫過一系列有關git-flow的介紹,至於github-flow的話就請參考最早的出處吧。

這一篇的重點如下:

  • Anything in the master branch is deployable
  • To work on something new, create a descriptively named branch off of master (ie: new-oauth2-scopes),
    • 也就是所謂的feature branch, 一個local branch, checkout到這個branch來開發
  • Commit to that branch locally and regularly push your work to the same named branch on the server
    • 然後在本地commit,push到同名的branch,git push origin [branch],然後就推上remote端(remote就是github上的code,origin是這個remote的名字)的那一個branch
  • When you need feedback or help, or you think the branch is ready for merging, open a pull request
    • 這一步好重要的,是用來code review的:當你把code push上去github的remote branch,pull request到你github的master branch,然後你的commit就會變成to be review status
  • After someone else has reviewed and signed off on the feature, you can merge it into master
    • review完之後,就可以準備merge 這個pull request回去master了
  • Once it is merged and pushed to ‘master’, you can and should deploy immediately
    • 而在本機端(local),你就可以準備回到master:git checkout mastergit pull origin master,把github上merge後的code再拉回本機端的master branch

接下來的Tealeaf課程就會用這一套做法來完成作業,首先先從pre-course的作業開始,當然這份作業已經是fork到我自己的repo,接下來要寫作業之前,就pull request。

先練習一下,我fork了matt的tealeaf作業修改一個地方,我的步驟如下:

  • 先到github網站上點擊fork,就會複製一份到我自己的github帳號底下
  • 回到我自己的gitgub打開my_postit這個repo,複製右邊的clone URL
  • 在terminal執行git clone git@github.com:Tim-Feng/my_postit.git
  • 切到目錄底下,用git checkout -b fix_sluggable創一個新的branch並且切過去
  • 開始修改。
  • git add .
  • git commit -m "modify sluggable"
  • push的時候有點問題,git ush origin fix_sluggable不能用,要用git push --set-upstream origin fix_sluggable才能push
  • 接下來就等matt回覆才能進行接下來的動作,不過流程基本上都清楚了。

到此為止是week 1第一段的lession,接下來是assignment,據說會需要經常的查看解答...所以預計會看很久,之後先暫時採取一篇lesson,一篇asignment的方式做記錄吧


[30 Coder(113), Day 331] Next Step
[30 Coder(112), Day 281] 廣告裁判 2 - Rails New Project
[30 Coder(111), Day 281] 廣告裁判 1 - 準備工作
[30 Coder(110), Day 268] Rails Digest 22 - jQury Preview
[30 Coder(109), Day 266] Rails Digest 21 - Facebook Login
[30 Coder(108), Day 265] Rails Digest 20 - Gravatar
[30 Coder(107), Day 265] Rails Digest 19 - Require Creator
[30 Coder(106), Day 261] Rails Digest 18 - Better Slug/Slug Module
[30 Coder(105), Day 260] Rails Digest 17 - Sluggify Post/Category/User
[30 Coder(104), Day 260] Rails Digest 16 - Push to Heroku
[30 Coder(103), Day 259] Rails Digest 15 - Edit/Show User
[30 Coder(102), Day 258] Rails Digest 14 - Register User
[30 Coder(101), Day 257] Rails Digest 13 - Authentication
[30 Coder(100), Day 257] Rails Digest 12 - has_secure_password
[30 Coder(99), Day 256] Rails Digest 11 - Helpers
[30 Coder(98), Day 255] Rails Digest 10 - Associate category
[30 Coder(97), Day 252] Rails Digest 9 - Errors Partial/Create Comment
[30 Coder(96), Day 251] Rails Digest 8 - Category
[30 Coder(95), Day 251] Rails Digest 7 - Set Post/Form Partial
[30 Coder(94), Day 250] Rails Digest 6 - Edit Post
[30 Coder(93), Day 249] Rails Digest 5 - New Post
[30 Coder(92), Day 249] Rails Digest 4 - Resources
[30 Coder(91), Day 248] Rails Digest 3 - Many to Many Association
[30 Coder(90), Day 248] Rails Digest 2 - Push to GitHub
[30 Coder(89), Day 246] Rails Digest 1 - First Models
[30 Coder(88), Day 245] Finished Tealeaf
[30 Coder(87), Day 244] Tea Leaf - Course 2 Week 4 Time Zones
[30 Coder(86), Day 244] Tea Leaf - Course 2 Week 4 Require Creator
[30 Coder(85), Day 244] Tea Leaf - Course 2 Week 4 Simple Roles
[30 Coder(84), Day 242] Tea Leaf - Course 2 Week 4 Voteable Gem
[30 Coder(83), Day 242] Tea Leaf - Course 2 Week 4 Sluggable Module
[30 Coder(82), Day 242] Tea Leaf - Course 2 Week 4 Voteable Module
[30 Coder(81), Day 242] Tea Leaf - Course 2 Week 4 Better Slugs
[30 Coder(80), Day 242] Tea Leaf - Course 2 Week 4 Sluggify Categories/Users
[30 Coder(79), Day 241] Tea Leaf - Course 2 Week 4 Sluggify Posts
[30 Coder(78), Day 240] Tea Leaf - Course 2 Week 4 Ajaxify Comment Votes
[30 Coder(77), Day 240] Tea Leaf - Course 2 Week 4 Ajaxify Post Votes
[30 Coder(76), Day 239] Ruby on Rails新手村
[30 Coder(75), Day 238] Tea Leaf - Course 2 Week 3 Vote Validation/Deploy to Heroku
[30 Coder(74), Day 238] Tea Leaf - Course 2 Week 3 Comment Vote
[30 Coder(73), Day 237] Tea Leaf - Course 2 Week 3 Post Votes-2
[30 Coder(72), Day 236] Tea Leaf - Course 2 Week 3 Post Votes-1
[30 Coder(71), Day 235] Tea Leaf - Course 2 Week 3 Polymorphic Vote
[30 Coder(70), Day 235] Tea Leaf - Course 2 Week 3 Edit/Show User
[30 Coder(69), Day 231] Tea Leaf - Course 2 Week 3 Authenticate/Register
[30 Coder(68), Day 225] Tea Leaf - Course 2 Week 2 - Form, Review
[30 Coder(67), Day 224] Tea Leaf - Course 2 Week 2 - Form, done
[30 Coder(66), Day 222] Tea Leaf - Course 2 Week 2 - Form
[30 Coder(65), Day 219] Tea Leaf - Course 2 Week 1 - Quiz 1 by classmate
[30 Coder(64), Day 219] Tea Leaf - Course 2 Week 1 - Quiz 1
[30 Coder(63), Day 218] Tea Leaf - Course 2 Week 1 - Resources: Post, Finally
[30 Coder(62), Day 217] Tea Leaf - Course 2 Week 1 - Resources: Post, Again
[30 Coder(61), Day 216] Tea Leaf - Course 2 Week 1 - Resources: Posts
[30 Coder(60), Day 216] Tea Leaf - Course 2 Week 1 - Category Model M:M Association
[30 Coder(59), Day 216] Tea Leaf - Course 2 Week 1 - Comment Model Association
[30 Coder(58), Day 215] Tea Leaf - Course 2 Week 1
[30 Coder(57), Day 215] Tea Leaf - Getting Started with Rails (on hold)
[30 Coder(56), Day 211] Tea Leaf - Getting Started with Rails
[30 Coder(55), Day 209] Tea Leaf - Reading Assignment: Relational Database
[30 Coder(54), Day 208] Tea Leaf - Ruby Exceptions and Exception Handling
[30 Coder(53), Day 205] Tea Leaf - Blackjack Web Version 8/8
[30 Coder(52), Day 203] Tea Leaf - Blackjack Web Version 7/8
[30 Coder(51), Day 201] Tea Leaf - Blackjack Web Version 6/6
[30 Coder(50), Day 201] Tea Leaf - Blackjack Web Version 5/6
[30 Coder(49), Day 201] Tea Leaf - Blackjack Web Version 4/6
[30 Coder(48), Day 200] Tea Leaf - Blackjack Web Version 3/6
[30 Coder(47), Day 198] Tea Leaf - Blackjack Web Version 2/6
[30 Coder(46), Day 198] Tea Leaf - Blackjack Web Version 1/6
[30 Coder(45), Day 198] Tea Leaf - Sinatra
[30 Coder(44), Day 196] Tea Leaf - Back to HTML/CSS
[30 Coder(43), Day 195] Tea Leaf - Object Oriented Blackjack
[30 Coder(42), Day 191] Tea Leaf - Week 2 Note 1
[30 Coder(41), Day 190] Tea Leaf - Oriented Object Programming
[30 Coder(40), Day 189] Tea Leaf - Week 1 Quiz
[30 Coder(39), Day 188] Tea Leaf - Learn to Program Ch11-15
[30 Coder(38), Day 185] Tea Leaf - Learn to Program Ch10
[30 Coder(37), Day 184] Tea Leaf - Ruby Style Guide
[30 Coder(36), Day 183] Tea Leaf - Blackjack
[30 Coder(35), Day 182] Tea Leaf - Ruby Style Guide
[30 Coder(34), Day 181] Tea Leaf - The First Class
[30 Coder(33), Day 178] Tea Leaf - Ruby Exercise
[30 Coder(32), Day 177] Tea Leaf Pre-course 1 Re-read Learn to Program
[30 Coder(31), Day 175] Tea Leaf Pre-course 1 Conclusion
[30 Coder(30), Day 174] Tea Leaf Pre-course of Course 1 - Learn to Program ch 9
[30 Coder(29), Day 171] Tea Leaf Pre-course of Course 1 - Learn to Program ch 8
[30 Coder(28), Day 170] Tea Leaf Pre-course of Course 1 - Learn to Program ch 1-7
[30 Coder(27), Day 169] Tea Leaf Pre-course of Course 1 - Learn to Program
[30 Coder(26), Day 168] Tea Leaf Pre-course of Course 1 - Command Line
[30 Coder(25), Day 167] Tea Leaf Pre-course of Course 1
[30 Coder(24), Day 164] I am all-in
[30 Coder(23), Day 159] It is Ruby on Rails
[30 Coder(22), Day 152] One Month Rails Finish
[30 Coder(21), Day 140] More Rails
[30 Coder(20), Day 130] Rails
[30 Coder(19), Day 122] Ruby
[30 Coder(18), Day 108] GitHub
[30 Coder(17), Day 101] End of Front-end
[30 Coder(16), Day 81] 盤點整理
[30 Coder(15), Day 70] JavaScript, AJAX, Apache
[30 Coder(14), Day 70] JavaScript, Movebox
[30 Coder(13), Day 51] JavaScript, 事件觸發
[30 Coder(12), Day 49] JavaScript, 判斷兩條線是否平行
[30 Coder(11), Day 46] JavaScript, 判斷質數
[30 Coder(10), Day 44] JavaScript
[30 Coder(9), Day 40] CSS定位
[30 Coder(8), Day 37] CSS
[30 Coder(7), Day 30] HTML
[30 Coder(6), Day 25] 起始狀態!
[30 Coder(5), Day 24] 成為你自己的技術創辦人(四)建立原型不可不知六件事
[30 Coder(4), Day 22] 成為你自己的技術創辦人(三)僱個工程師還是DIY?
[30 Coder(3), Day 15] 成為你自己的技術創辦人(二)找不到, 自己來
[30 Coder(2), Day 8] 成為你自己的技術創辦人(一)尋找技術合夥人指南
[30 Coder(1), Day 1] Every Startup Has A Beginning

[30 Coder, 114] Tealeaf Course 3 再開!

我終於成為一位Rails程序員了,而且是在一間新創公司,廣告裁判也已經上線在測試,目前自我感覺非常踏實。

不過新工作還是得先站穩腳步,所以考慮到接下來的工作內容非常需要測試來輔助開發,我決定開始上Tealeaf的course 3,學習怎麼做測試,照例會用這個blog留下記錄,如果有錯,還請不吝指正。

Course 3的precourse重點在於環境的setup,並介紹了HAML,還有如何從mockup逐步地做成網站的概念,這邊就略過不表,下一篇直接進入week 1。

[30 Coder(113), Day 331] Nxt Step
[30 Coder(112), Day 281] 廣告裁判 2 - Rails New Project
[30 Coder(111), Day 281] 廣告裁判 1 - 準備工作
[30 Coder(110), Day 268] Rails Digest 22 - jQury Preview
[30 Coder(109), Day 266] Rails Digest 21 - Facebook Login
[30 Coder(108), Day 265] Rails Digest 20 - Gravatar
[30 Coder(107), Day 265] Rails Digest 19 - Require Creator
[30 Coder(106), Day 261] Rails Digest 18 - Better Slug/Slug Module
[30 Coder(105), Day 260] Rails Digest 17 - Sluggify Post/Category/User
[30 Coder(104), Day 260] Rails Digest 16 - Push to Heroku
[30 Coder(103), Day 259] Rails Digest 15 - Edit/Show User
[30 Coder(102), Day 258] Rails Digest 14 - Register User
[30 Coder(101), Day 257] Rails Digest 13 - Authentication
[30 Coder(100), Day 257] Rails Digest 12 - has_secure_password
[30 Coder(99), Day 256] Rails Digest 11 - Helpers
[30 Coder(98), Day 255] Rails Digest 10 - Associate category
[30 Coder(97), Day 252] Rails Digest 9 - Errors Partial/Create Comment
[30 Coder(96), Day 251] Rails Digest 8 - Category
[30 Coder(95), Day 251] Rails Digest 7 - Set Post/Form Partial
[30 Coder(94), Day 250] Rails Digest 6 - Edit Post
[30 Coder(93), Day 249] Rails Digest 5 - New Post
[30 Coder(92), Day 249] Rails Digest 4 - Resources
[30 Coder(91), Day 248] Rails Digest 3 - Many to Many Association
[30 Coder(90), Day 248] Rails Digest 2 - Push to GitHub
[30 Coder(89), Day 246] Rails Digest 1 - First Models
[30 Coder(88), Day 245] Finished Tealeaf
[30 Coder(87), Day 244] Tea Leaf - Course 2 Week 4 Time Zones
[30 Coder(86), Day 244] Tea Leaf - Course 2 Week 4 Require Creator
[30 Coder(85), Day 244] Tea Leaf - Course 2 Week 4 Simple Roles
[30 Coder(84), Day 242] Tea Leaf - Course 2 Week 4 Voteable Gem
[30 Coder(83), Day 242] Tea Leaf - Course 2 Week 4 Sluggable Module
[30 Coder(82), Day 242] Tea Leaf - Course 2 Week 4 Voteable Module
[30 Coder(81), Day 242] Tea Leaf - Course 2 Week 4 Better Slugs
[30 Coder(80), Day 242] Tea Leaf - Course 2 Week 4 Sluggify Categories/Users
[30 Coder(79), Day 241] Tea Leaf - Course 2 Week 4 Sluggify Posts
[30 Coder(78), Day 240] Tea Leaf - Course 2 Week 4 Ajaxify Comment Votes
[30 Coder(77), Day 240] Tea Leaf - Course 2 Week 4 Ajaxify Post Votes
[30 Coder(76), Day 239] Ruby on Rails新手村
[30 Coder(75), Day 238] Tea Leaf - Course 2 Week 3 Vote Validation/Deploy to Heroku
[30 Coder(74), Day 238] Tea Leaf - Course 2 Week 3 Comment Vote
[30 Coder(73), Day 237] Tea Leaf - Course 2 Week 3 Post Votes-2
[30 Coder(72), Day 236] Tea Leaf - Course 2 Week 3 Post Votes-1
[30 Coder(71), Day 235] Tea Leaf - Course 2 Week 3 Polymorphic Vote
[30 Coder(70), Day 235] Tea Leaf - Course 2 Week 3 Edit/Show User
[30 Coder(69), Day 231] Tea Leaf - Course 2 Week 3 Authenticate/Register
[30 Coder(68), Day 225] Tea Leaf - Course 2 Week 2 - Form, Review
[30 Coder(67), Day 224] Tea Leaf - Course 2 Week 2 - Form, done
[30 Coder(66), Day 222] Tea Leaf - Course 2 Week 2 - Form
[30 Coder(65), Day 219] Tea Leaf - Course 2 Week 1 - Quiz 1 by classmate
[30 Coder(64), Day 219] Tea Leaf - Course 2 Week 1 - Quiz 1
[30 Coder(63), Day 218] Tea Leaf - Course 2 Week 1 - Resources: Post, Finally
[30 Coder(62), Day 217] Tea Leaf - Course 2 Week 1 - Resources: Post, Again
[30 Coder(61), Day 216] Tea Leaf - Course 2 Week 1 - Resources: Posts
[30 Coder(60), Day 216] Tea Leaf - Course 2 Week 1 - Category Model M:M Association
[30 Coder(59), Day 216] Tea Leaf - Course 2 Week 1 - Comment Model Association
[30 Coder(58), Day 215] Tea Leaf - Course 2 Week 1
[30 Coder(57), Day 215] Tea Leaf - Getting Started with Rails (on hold)
[30 Coder(56), Day 211] Tea Leaf - Getting Started with Rails
[30 Coder(55), Day 209] Tea Leaf - Reading Assignment: Relational Database
[30 Coder(54), Day 208] Tea Leaf - Ruby Exceptions and Exception Handling
[30 Coder(53), Day 205] Tea Leaf - Blackjack Web Version 8/8
[30 Coder(52), Day 203] Tea Leaf - Blackjack Web Version 7/8
[30 Coder(51), Day 201] Tea Leaf - Blackjack Web Version 6/6
[30 Coder(50), Day 201] Tea Leaf - Blackjack Web Version 5/6
[30 Coder(49), Day 201] Tea Leaf - Blackjack Web Version 4/6
[30 Coder(48), Day 200] Tea Leaf - Blackjack Web Version 3/6
[30 Coder(47), Day 198] Tea Leaf - Blackjack Web Version 2/6
[30 Coder(46), Day 198] Tea Leaf - Blackjack Web Version 1/6
[30 Coder(45), Day 198] Tea Leaf - Sinatra
[30 Coder(44), Day 196] Tea Leaf - Back to HTML/CSS
[30 Coder(43), Day 195] Tea Leaf - Object Oriented Blackjack
[30 Coder(42), Day 191] Tea Leaf - Week 2 Note 1
[30 Coder(41), Day 190] Tea Leaf - Oriented Object Programming
[30 Coder(40), Day 189] Tea Leaf - Week 1 Quiz
[30 Coder(39), Day 188] Tea Leaf - Learn to Program Ch11-15
[30 Coder(38), Day 185] Tea Leaf - Learn to Program Ch10
[30 Coder(37), Day 184] Tea Leaf - Ruby Style Guide
[30 Coder(36), Day 183] Tea Leaf - Blackjack
[30 Coder(35), Day 182] Tea Leaf - Ruby Style Guide
[30 Coder(34), Day 181] Tea Leaf - The First Class
[30 Coder(33), Day 178] Tea Leaf - Ruby Exercise
[30 Coder(32), Day 177] Tea Leaf Pre-course 1 Re-read Learn to Program
[30 Coder(31), Day 175] Tea Leaf Pre-course 1 Conclusion
[30 Coder(30), Day 174] Tea Leaf Pre-course of Course 1 - Learn to Program ch 9
[30 Coder(29), Day 171] Tea Leaf Pre-course of Course 1 - Learn to Program ch 8
[30 Coder(28), Day 170] Tea Leaf Pre-course of Course 1 - Learn to Program ch 1-7
[30 Coder(27), Day 169] Tea Leaf Pre-course of Course 1 - Learn to Program
[30 Coder(26), Day 168] Tea Leaf Pre-course of Course 1 - Command Line
[30 Coder(25), Day 167] Tea Leaf Pre-course of Course 1
[30 Coder(24), Day 164] I am all-in
[30 Coder(23), Day 159] It is Ruby on Rails
[30 Coder(22), Day 152] One Month Rails Finish
[30 Coder(21), Day 140] More Rails
[30 Coder(20), Day 130] Rails
[30 Coder(19), Day 122] Ruby
[30 Coder(18), Day 108] GitHub
[30 Coder(17), Day 101] End of Front-end
[30 Coder(16), Day 81] 盤點整理
[30 Coder(15), Day 70] JavaScript, AJAX, Apache
[30 Coder(14), Day 70] JavaScript, Movebox
[30 Coder(13), Day 51] JavaScript, 事件觸發
[30 Coder(12), Day 49] JavaScript, 判斷兩條線是否平行
[30 Coder(11), Day 46] JavaScript, 判斷質數
[30 Coder(10), Day 44] JavaScript
[30 Coder(9), Day 40] CSS定位
[30 Coder(8), Day 37] CSS
[30 Coder(7), Day 30] HTML
[30 Coder(6), Day 25] 起始狀態!
[30 Coder(5), Day 24] 成為你自己的技術創辦人(四)建立原型不可不知六件事
[30 Coder(4), Day 22] 成為你自己的技術創辦人(三)僱個工程師還是DIY?
[30 Coder(3), Day 15] 成為你自己的技術創辦人(二)找不到, 自己來
[30 Coder(2), Day 8] 成為你自己的技術創辦人(一)尋找技術合夥人指南
[30 Coder(1), Day 1] Every Startup Has A Beginning