├── organize ├── 7_gem.md ├── 0_organize.md ├── 5_meta_programming.md ├── 6_routing.md ├── 1_view.md ├── 3_model.md └── 2_controller.md ├── Gemfile ├── advertise ├── 0_advertise.md ├── 1_we_are_hiring.md ├── 2_rails_101.md ├── cover_xdite.png └── 3_essential_rails.md ├── .gitignore ├── config.ru ├── .DS_Store ├── ruby.png ├── our_way_to_organize ├── 00_our_way_to_organize.md ├── cell.png ├── 05_css.md ├── 03_controller.md ├── 06_library.md ├── 09_cache.md ├── 04_helper.md ├── 10_expensive_jobs.md ├── 08_settings.md ├── 07_permission.md ├── 11_crontab.md ├── 02_view.md └── 01_model.md ├── the_end └── the_end.md ├── techbang-icon.png ├── about_me ├── techbang.png ├── techbang-logo.png └── about_me.md ├── title └── 01_slide.md ├── bad_code ├── spaghetti.jpg ├── book-of-ruby.jpg ├── eloquent-ruby.jpg ├── wrong-camel-style.png ├── wrong-coding-style.png ├── simliar-but-different.png ├── inconsist-coding-style.png └── bad_code.md ├── .sass-cache ├── 07c439246232fad564fe89c3b8e897fb229dfd19 │ ├── print.scssc │ ├── rubyconftw.scssc │ ├── ie.scssc │ └── screen.scssc ├── cc68b714c1a90de69617ba28e081c40ad837bc40 │ ├── print.scssc │ ├── ie.scssc │ └── screen.scssc ├── 43f7c6b2e81259f9e9671279ae9f5f1c9c2a1340 │ └── _utilities.scssc ├── d2c0c7052f2630646a265a48e656c8574dbd36b6 │ └── _utilities.scssc ├── e80ff0030fc1b1505cd912f413dc30f2caab65de │ └── _utilities.scssc ├── 3bda273ae1167db8c681ac4d0c35b65945d2d032 │ └── _reset.scssc ├── 724a8e4f1c9bf41ba998c29a69300352d4dc2833 │ └── _reset.scssc └── 1d8aa3db07720ffbd41ce6b7461fa25fa8bc97a4 │ └── _reset.scssc ├── sass ├── print.scss ├── ie.scss ├── screen.scss └── rubyconftw.scss ├── stylesheets ├── print.css ├── ie.css ├── rubyconftw.css └── screen.css ├── reference └── reference.md ├── agenda └── agenda.md ├── showoff.json ├── Gemfile.lock ├── conclusion └── conclusion.md ├── reinvent_wheels └── reinvent_wheels.md ├── config.rb ├── rubyconftw.css ├── mvc └── mvc.md ├── abusing_rails └── abusing_rails.md └── compass_app_log.txt /organize/7_gem.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source :rubygems 2 | gem "showoff" -------------------------------------------------------------------------------- /advertise/0_advertise.md: -------------------------------------------------------------------------------- 1 | !SLIDE 2 | 3 | # 廣告時間 -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .redcar/ 2 | tmp/ 3 | .sass-cache/ 4 | .DS_store -------------------------------------------------------------------------------- /config.ru: -------------------------------------------------------------------------------- 1 | require "rubygems" 2 | require "showoff" 3 | run ShowOff.new 4 | -------------------------------------------------------------------------------- /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdite/essential-rails-pattern/HEAD/.DS_Store -------------------------------------------------------------------------------- /ruby.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdite/essential-rails-pattern/HEAD/ruby.png -------------------------------------------------------------------------------- /advertise/1_we_are_hiring.md: -------------------------------------------------------------------------------- 1 | !SLIDE 2 | 3 | # We are hiring!! 4 | ## job@techbang.com.tw -------------------------------------------------------------------------------- /our_way_to_organize/00_our_way_to_organize.md: -------------------------------------------------------------------------------- 1 | !SLIDE 2 | 3 | ## HOW we organize our code? 4 | -------------------------------------------------------------------------------- /the_end/the_end.md: -------------------------------------------------------------------------------- 1 | !SLIDE 2 | 3 | # THE END 4 | 5 | ### http://bit.ly/rubyconftw-2011-xdite -------------------------------------------------------------------------------- /techbang-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdite/essential-rails-pattern/HEAD/techbang-icon.png -------------------------------------------------------------------------------- /about_me/techbang.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdite/essential-rails-pattern/HEAD/about_me/techbang.png -------------------------------------------------------------------------------- /title/01_slide.md: -------------------------------------------------------------------------------- 1 | !SLIDE 2 | # Essential Rails Design Pattern # 3 | 4 | ## write maintainable Rails code -------------------------------------------------------------------------------- /bad_code/spaghetti.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdite/essential-rails-pattern/HEAD/bad_code/spaghetti.jpg -------------------------------------------------------------------------------- /about_me/techbang-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdite/essential-rails-pattern/HEAD/about_me/techbang-logo.png -------------------------------------------------------------------------------- /advertise/2_rails_101.md: -------------------------------------------------------------------------------- 1 | !SLIDE 2 | 3 | ## Rails 101 特價中 $4.99 USD (只到 8 / 27 ) 4 | ### http://blog.xdite.net/?p=3046 -------------------------------------------------------------------------------- /advertise/cover_xdite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdite/essential-rails-pattern/HEAD/advertise/cover_xdite.png -------------------------------------------------------------------------------- /bad_code/book-of-ruby.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdite/essential-rails-pattern/HEAD/bad_code/book-of-ruby.jpg -------------------------------------------------------------------------------- /bad_code/eloquent-ruby.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdite/essential-rails-pattern/HEAD/bad_code/eloquent-ruby.jpg -------------------------------------------------------------------------------- /our_way_to_organize/cell.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdite/essential-rails-pattern/HEAD/our_way_to_organize/cell.png -------------------------------------------------------------------------------- /bad_code/wrong-camel-style.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdite/essential-rails-pattern/HEAD/bad_code/wrong-camel-style.png -------------------------------------------------------------------------------- /bad_code/wrong-coding-style.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdite/essential-rails-pattern/HEAD/bad_code/wrong-coding-style.png -------------------------------------------------------------------------------- /bad_code/simliar-but-different.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdite/essential-rails-pattern/HEAD/bad_code/simliar-but-different.png -------------------------------------------------------------------------------- /bad_code/inconsist-coding-style.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdite/essential-rails-pattern/HEAD/bad_code/inconsist-coding-style.png -------------------------------------------------------------------------------- /.sass-cache/07c439246232fad564fe89c3b8e897fb229dfd19/print.scssc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdite/essential-rails-pattern/HEAD/.sass-cache/07c439246232fad564fe89c3b8e897fb229dfd19/print.scssc -------------------------------------------------------------------------------- /.sass-cache/cc68b714c1a90de69617ba28e081c40ad837bc40/print.scssc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdite/essential-rails-pattern/HEAD/.sass-cache/cc68b714c1a90de69617ba28e081c40ad837bc40/print.scssc -------------------------------------------------------------------------------- /.sass-cache/07c439246232fad564fe89c3b8e897fb229dfd19/rubyconftw.scssc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdite/essential-rails-pattern/HEAD/.sass-cache/07c439246232fad564fe89c3b8e897fb229dfd19/rubyconftw.scssc -------------------------------------------------------------------------------- /.sass-cache/43f7c6b2e81259f9e9671279ae9f5f1c9c2a1340/_utilities.scssc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdite/essential-rails-pattern/HEAD/.sass-cache/43f7c6b2e81259f9e9671279ae9f5f1c9c2a1340/_utilities.scssc -------------------------------------------------------------------------------- /.sass-cache/d2c0c7052f2630646a265a48e656c8574dbd36b6/_utilities.scssc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdite/essential-rails-pattern/HEAD/.sass-cache/d2c0c7052f2630646a265a48e656c8574dbd36b6/_utilities.scssc -------------------------------------------------------------------------------- /.sass-cache/e80ff0030fc1b1505cd912f413dc30f2caab65de/_utilities.scssc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xdite/essential-rails-pattern/HEAD/.sass-cache/e80ff0030fc1b1505cd912f413dc30f2caab65de/_utilities.scssc -------------------------------------------------------------------------------- /our_way_to_organize/05_css.md: -------------------------------------------------------------------------------- 1 | !SLIDE 2 | 3 | # CSS 4 | 5 | !SLIDE bullets left 6 | 7 | # Compass 8 | 9 | * 使用 SCSS 撰寫 CSS 10 | * orgnize by controller / component 11 | * extract common css (IE hack, CSS 圓角, 按鈕, 表單 ) 12 | * partial -------------------------------------------------------------------------------- /sass/print.scss: -------------------------------------------------------------------------------- 1 | /* Welcome to Compass. Use this file to define print styles. 2 | * Import this file using the following HTML or equivalent: 3 | * */ 4 | -------------------------------------------------------------------------------- /stylesheets/print.css: -------------------------------------------------------------------------------- 1 | /* Welcome to Compass. Use this file to define print styles. 2 | * Import this file using the following HTML or equivalent: 3 | * */ 4 | -------------------------------------------------------------------------------- /organize/0_organize.md: -------------------------------------------------------------------------------- 1 | !SLIDE 2 | 3 | # 專案程式碼過於冗長僵硬 4 | ## 大家最想解決的問題 5 | 6 | !SLIDE 7 | 8 | ## 讓我們來學幾招整理術吧 9 | 10 | !SLIDE bullets left 11 | 12 | # Agenda 13 | 14 | * View 15 | * Controlller 16 | * Model 17 | * Routing 18 | * Advanced: Meta Programming -------------------------------------------------------------------------------- /reference/reference.md: -------------------------------------------------------------------------------- 1 | !SLIDE bullets left 2 | 3 | # 參考資料 4 | 5 | * T客邦內部開發經驗 6 | * Ruby Style Guide 7 | * Rails best practices - by ihower 8 | * Rails AntiPattern - Pragmatic BookShelf 9 | * Rails3 Way - Addison-Wesley 10 | * Write Efficiency Ruby code - Addison-Wesley -------------------------------------------------------------------------------- /our_way_to_organize/03_controller.md: -------------------------------------------------------------------------------- 1 | !SLIDE 2 | 3 | # Controller 4 | 5 | !SLIDE bullets left 6 | 7 | ## Controller 8 | 9 | * 雙層 resources 10 | - 三層以上請拆成雙層 11 | - sites / boards 12 | - boards / topics 13 | * Namespace 14 | - admin/ 15 | - panel/ 16 | 17 | 18 | -------------------------------------------------------------------------------- /sass/ie.scss: -------------------------------------------------------------------------------- 1 | /* Welcome to Compass. Use this file to write IE specific override styles. 2 | * Import this file using the following HTML or equivalent: 3 | * */ 6 | -------------------------------------------------------------------------------- /stylesheets/ie.css: -------------------------------------------------------------------------------- 1 | /* Welcome to Compass. Use this file to write IE specific override styles. 2 | * Import this file using the following HTML or equivalent: 3 | * */ 6 | -------------------------------------------------------------------------------- /agenda/agenda.md: -------------------------------------------------------------------------------- 1 | !SLIDE 2 | 3 | # Why this talk? 4 | 5 | !SLIDE bullets left 6 | 7 | # 本日大綱 8 | 9 | * 為什麼 Code 會腐敗? 10 | * 無法維護的 Rails Code 11 | * 如何整理 Rails Code 12 | * Rails native mechanism 13 | * 使用 RubyGem 整理設計程式碼 14 | 15 | !SLIDE 16 | 17 | ## http://bit.ly/rubyconftw-2011-xdite 18 | ### 本 talk 網址 19 | -------------------------------------------------------------------------------- /sass/screen.scss: -------------------------------------------------------------------------------- 1 | /* Welcome to Compass. 2 | * In this file you should write your main styles. (or centralize your imports) 3 | * Import this file using the following HTML or equivalent: 4 | * */ 5 | 6 | @import "compass/reset"; 7 | -------------------------------------------------------------------------------- /about_me/about_me.md: -------------------------------------------------------------------------------- 1 | !SLIDE bullets left aboutme 2 | 3 | # About Me # 4 | 5 | * 鄭伊廷 / xdite 6 | * http://blog.xdite.net 7 | * http://gplus.to/xdite 8 | * xdite@techbang.com.tw 9 | 10 | !SLIDE center 11 | 12 |
14 |
5 | 13 | gem "techbang-authentication", 14 | :git => "git@github.com:techbang/techbang-authentication.git", 15 | :tag => "0.1.0" 16 |17 |
18 | 15 | helper HandicraftHelper 16 | helper TechbangHelper 17 |18 |
13 | ["maple", "wow", "diablo3"].each do |key,value|
14 | define_method("#{key}_game") do
15 | find_by_name(value)
16 | end
17 | end
18 |
19 | 25 | find_by_post_id_and_user_id 26 | find_or_initialize_by_ooo_and_xxx 27 |
22 |
23 | class NewsletterJob < Struct.new(:text, :emails)
24 | def perform
25 | emails.each { |e| NewsletterMailer.deliver_text_to_email(text, e) }
26 | end
27 | end
28 |
29 | 19 | development: &DEV 20 | techbang_cas_base_url: "https://s.dev" 21 | techbang_profile_app_url: "https://i.dev" 22 | techbang_ads_app_url: "http://ads.dev" 23 | 24 | production: 25 | techbang_cas_base_url: "https://s.techbang.com.tw" 26 | techbang_profile_app_url: "https://i.techbang.com.tw" 27 | techbang_ads_app_url: "http://ads.techbang.com.tw" 28 |29 |
12 | class Ability 13 | include CanCan::Ability 14 | 15 | def initialize(user) 16 | if user.has_role?(:admin) 17 | admin_permissions(user) 18 | elsif user.has_role?(:editor) 19 | editor_permissions(user) 20 | elsif user.has_role?(:author) 21 | author_permissions(user) 22 | elsif user.has_role?(:marketing) 23 | marketing_permissions(user) 24 | elsif user.has_role?(:contributor) 25 | cannot :manage, :all 26 | else 27 | cannot :manage, :all 28 | end 29 | end 30 |31 |
11 | class UsersController < ApplicationController 12 | def add_friend 13 | # .... 14 | end 15 | 16 | def add_to_favorites 17 | # .... 18 | end 19 | end 20 |21 |
29 | class User::FriendsController < ApplicationController 30 | def create 31 | # ... 32 | end 33 | end 34 | 35 | class User::FavoritesController < ApplicationController 36 | def create 37 | # ... 38 | end 39 | end 40 | 41 |42 |
13 | every 3.hours do 14 | runner "MyModel.some_process" 15 | rake "my:rake:task" 16 | command "/usr/bin/my_great_command" 17 | end 18 | 19 | every 1.day, :at => '4:30 am' do 20 | runner "DB.Backup" 21 | end 22 | 23 | every :hour do # Many shortcuts available: :hour, :day, :month, :year, :reboot 24 | runner "SomeModel.ladeeda" 25 | end 26 | 27 | every :sunday do # Use any day of the week or :weekend, :weekday 28 | runner "Task.do_something_great" 29 | end 30 |31 |
9 | <!DOCTYPE html> 10 | <html> 11 | 12 | <head> 13 | <meta charset="utf-8"> 14 | <%= render_page_title %> 15 | <%= stylesheet_link_tag :all %> 16 | <%= csrf_meta_tag %> 17 | </head> 18 | 19 |20 |
25 | <%= render_body_tag %> 26 | <div id="header"> 27 | <%= render :partial => "common/header"%> 28 | </div> 29 | 30 | <div id="content"> 31 | <%= render_stickies %> 32 | <div id="main"> 33 | <%= yield %> 34 | </div> 35 | <div id="sidebar"> 36 | <%= yield(:sidebar)%> 37 | </div> 38 | </div> 39 | 40 |41 |
46 | 47 | <div id="footer"> 48 | <%= render :partial => "common/footer" %> 49 | </div> 50 | 51 | <%= javascript_includes_tag :all %> 52 | <%= yield(:page_specific_javascript)%> 53 | 54 | </body> 55 | </html> 56 |57 |
12 | <div id="header"> 13 | 14 | <div class="group"> 15 | 16 | <%= render :partial => "common/user_navigation" %> 17 | 18 | <%= render :partial => "common/header" %> 19 | 20 | </div> 21 | 22 | <%= render :partial => "common/network" %> 23 | 24 | <%= render :partial => "common/man_navigation" %> 25 | 26 | <aside><%= ads_in_layout_top %></aside> 27 | 28 | </div> 29 |30 |
40 | <article class="articles"> 41 | 42 | <%= render :partial => "posts/s_post", 43 | :collection => @new_posts, :as => :post %> 44 | 45 | <%= render :partial => "posts/apost", 46 | :collection => @advertise_posts :as => :post %> 47 | 48 | </article> 49 |50 |
65 | <span>發表於 <%= l(@post.published_at, :format => :long) %></span> 66 |67 |
73 | <span>發表於 <%= render_published_at(@post) %></span> 74 |75 |
38 | <% if current_user && current_user == post.user %>
39 | <%= link_to("Edit", edit_post_path(post))%>
40 | <% end %>
41 |
42 |
48 | <% if editable?(post) %>
49 | <%= link_to("Edit", edit_post_path(post))%>
50 | <% end %>
51 |
52 | 62 | def checkout 63 | book = Book.find(params[:id]) 64 | current_user.balance -= book.price 65 | curremt_user.save! 66 | redirect_to account_path 67 | end 68 |69 |
75 | def checkout 76 | book = Book.find(params[:id]) 77 | current_user.purchase(book) 78 | redirect_to account_path 79 | end 80 |81 |
93 | def tag_list_for_welcome_page
94 | tags.maps {|tag| "<span> tag.name </span>" }.join(" / ")
95 | end
96 |
97 |
104 | def tag_list(tags)
105 | tags.map { |tag| content_tag(:span, tag.name ) }.join(" / ")
106 | end
107 |
108 | 11 | # 一律先把需要的 lib 都加入 12 | require "nokogiri" 13 | 14 | class Post < ActiveRecord::Base 15 | # 先把需要的 module 都加入 16 | include Techbang::Goodies 17 | 18 | # 宣告 class accessor、類別變數、常數 19 | cattr_reader :per_page 20 | @@per_page = 10 21 | DEFAULT_AUTHOR = "you" 22 | 23 | # 宣告 instance accessor、序列化的資料欄位、可以存取的欄位 24 | 25 | attr_reader :headline_image 26 | serialize :exif 27 | attr_accessible :title, :excerpt, :description 28 | 29 | # 宣告各式 validation 和 validation filter 30 | validates_presence_of :title, :published_at 31 | before_validation :ensure_title 32 | 33 | # 宣告 has_many、belongs_to、has_and_belongs_to_many 等 association 關係 34 | belongs_to :user, :counter_cache => true 35 | has_many :comments, :as => :resource 36 |37 |
44 | # 如果有 delegate 則寫在那個 association 下 45 | has_one :profile 46 | accepts_nested_attributes_for :profile 47 | delegate :resume, :blog_url, :facebook_url, :plurk_url, :twitter_url, :to => :profile 48 | 49 | # 宣告 gem 的 class method,通常我會把這個 gem 相關的 method 放一起 50 | has_attached_file :image 51 | validates_attachment_content_type :image 52 | validates_attachment_size :image 53 | after_image_post_process :get_exif 54 | delegate :url, :to => :image 55 | 56 | acts_as_taggable_on :tags 57 | chinese_permalink :title 58 | 59 | define_index do 60 | indexes title 61 | indexes description 62 | end 63 | 64 | # 宣告各式 filter/callback 65 | before_save :build_profile, :if => "profile.nil?" 66 | after_save :save_profile 67 | 68 | !SLIDE code 69 | 70 | ## 續 71 |72 |99 | 100 | !SLIDE 101 | 102 | ## Annotate 103 | 104 |73 | 74 | # 宣告各式 scope 定義 75 | scope :recent, lambda { |amount| order(""published_at DESC"").limit(amount || 5) } 76 | 77 | # 宣告 class method 78 | def self.published(post_types=[self.to_s]) 79 | where(:type => post_types).where(:aasm_state => "published").where(["published_at <= ?", Time.zone.now]).order("published_at DESC") 80 | end 81 | 82 | # 宣告 instance method 83 | def is_published? 84 | aasm_state == "published" && published_at <= Time.zone.now 85 | end 86 | 87 | 88 | protected 89 | 90 | # .... 91 | 92 | private 93 | 94 | # .... 95 | 96 | end 97 |98 |105 |-------------------------------------------------------------------------------- /abusing_rails/abusing_rails.md: -------------------------------------------------------------------------------- 1 | !SLIDE 2 | 3 | # 濫用 Rails 內建機制 4 | ## 隱藏的炸彈 5 | 6 | !SLIDE code bullets left 7 | 8 | ## ABUSE: 濫用 helper 的 magic 9 | 10 |106 | # == Schema Information 107 | # 108 | # Table name: categories 109 | # 110 | # id :integer(4) not null, primary key 111 | # name :string(255) 112 | # label_id :integer(4) 113 | # is_list :boolean(1) default(TRUE) 114 | # for_marketing :boolean(1) default(FALSE) 115 | # for_admin :boolean(1) default(FALSE) 116 | # created_at :datetime 117 | # updated_at :datetime 118 | 119 |120 |11 |17 | 18 | ### 實作 STI 時,magic 針對 model type 展開,爆光光... 19 | ### 翻修時無法使用 git grep "xxxx_path" 快速找到可能有問題處 20 | 21 | !SLIDE code 22 | 23 | # ABUSE: ORM 無限串接 24 | 25 |12 | <%= form_for @model %> 13 | <%= form_for [@post,@comment] %> 14 | <%= link_to "mode_name", @model %> 15 |16 |
26 | 27 |28 |32 | 33 |29 | post.aa.bb.cc.dd.ee.ff.gg.hh.ii.jj.kk.ll.mm.nn.oo.pp 30 |31 |
34 | ### Create A LOT OF objects 35 | ### Complex JOIN & SLOW query 36 | 37 | !SLIDE bullets left 38 | 39 | ## Solution 40 | 41 | * 使用 scope 整理 code 42 | * 使用 method 整理 code 43 | * 使用 query_reviewer 檢查 query 44 | * 減少 join 的機會,使用多個 select 造出 query 45 | 46 | !SLIDE code 47 | 48 | ## ABUSE: 厭惡使用 RESTful 49 | 50 |51 |55 | 56 | ### 程式碼失去組織性 57 | ### !!! 嚴重的 security issue !!! 58 | 59 | 60 | !SLIDE bullets left 61 | 62 | ## 避免跨站偽造請求 Cross-site request forgery 63 | 64 | * 所有讀取、查詢性質操作,都應該用GET 65 | * 修改或刪除到資料的,則要用POST、PUT或DELETE 66 | * 所有的POST請求,都必須加上一個安全驗證碼 67 | 68 | 69 | !SLIDE code 70 | 71 | ## 內建機制 72 | app/controllers/application_controller.rb 73 |52 | # match ':controller(/:action(/:id(.:format)))' 53 |54 |74 |80 | 81 | app/views/layout/application.html.erb 82 |75 | class ApplicationController < ActionController::Base 76 | protect_from_forgery 77 | end 78 |79 |83 |87 | 88 | !SLIDE 89 | 90 |84 | <%= csrf_meta_tag %> 85 |86 |91 |95 | 96 | ## 硬幹就失去天然屏障了,任何 action 都可以 get 97 | 98 | !SLIDE center 99 | 100 | 101 |92 | # match ':controller(/:action(/:id(.:format)))' 93 |94 |102 |106 | 107 | !SLIDE 108 |103 | <img src="/posts/delete_all"> 104 |105 |109 |111 | 112 | !SLIDE 113 | ## Solution 114 | # RESTful ...... please!! 115 | 116 | !SLIDE code 117 | 118 | ## ABUSE: SQL Query in LOOP 119 |!! VERY DANGER !!
110 |120 |126 | 127 | ## Some operation is very EXPENSIVE 128 | 129 | !SLIDE bullets left 130 | 131 | ## Solution 132 | 133 | * cache expensive operation 134 | - ex. counter_cache, memorize, cache 135 | * includes 136 | * find\_in\_batch 137 | 138 | !SLIDE code 139 | ## abusing helper 140 | 141 |121 | <% Post.limit(10).each do |post| %> 122 | <%= post.categories.map{ |c| "<span>#{c.name}</span>"} =%> 123 | <% end %> 124 |125 |142 |155 | 156 | 157 | !SLIDE bullets left 158 | 159 | ## Solution 160 | 161 | * Never write plain html in helper 162 | * use content_tag in your helper 163 | * use "partial" to orgnize your code -------------------------------------------------------------------------------- /organize/3_model.md: -------------------------------------------------------------------------------- 1 | !SLIDE 2 | 3 | # Model 超過 2.5 頁請注意 4 | 5 | !SLIDE code 6 | 7 | ## Extract to Module 8 | 9 |143 | def post_information(post) 144 | content ||=" " 145 | content += "<div class=\"information\"> 146 | content += "<span class=\"author\">#{ post.author.name} </span>" 147 | content += "published at" 148 | content + = "<span class=\"time\"> #{ l(post.published_at, :format => short) </span>" 149 | content + = "</div>" 150 | return content 151 | end 152 |153 | 154 |10 |18 | 19 | !SLIDE code 20 | 21 | ### Common Behavior 22 | 23 |11 | class Post < ActiveRecord::Base 12 | include Techbang::PostBase 13 | 14 | # ... some bussiness logic method here 15 | end 16 |17 |24 |53 | 54 | !SLIDE left 55 | 56 | ## 使用 STI / NameSpace 57 | 58 | ### Single Table Inheritance 59 | 60 |25 | module Techbang 26 | module PostBase 27 | extend ActiveSupport::Concern 28 | included do 29 | included AASM 30 | include ExcerptMethods 31 | include ContentMethods 32 | include PermalinkMethods 33 | 34 | aasm_state :submitted, :enter => :notifiy_reviewer 35 | aasm_state :published 36 | 37 | before_save :randomize_excerpt_image_file_name 38 | 39 | end 40 | 41 | module ClassMethods 42 | end 43 | 44 | module InstanceMethods 45 | 46 | def is_scheduled? 47 | aasm_state == "published" && published_at > Time.zone.now 48 | end 49 | end 50 | end 51 |52 |61 |69 | 70 | ### NameSpace 71 | 72 |62 | class TechbangPost < Post 63 | end 64 | 65 | class AdvertisePost < Post 66 | end 67 |68 |73 |81 | 82 | !SLIDE code 83 | 84 | ## Extract to composed class 85 | 86 |74 | class User::Profile < ActiveRecord::Base 75 | end 76 | 77 | class User::Preference < ActiveRecord::Base 78 | end 79 |80 |87 |106 | 107 | !SLIDE 108 | 109 | ## 類似作用與名稱的 Model 超過 2 個請注意 110 | 111 | !SLIDE code 112 | 113 | ## Polymorphic Association 114 | 115 | ### Bad Smell 116 | 117 |88 | class Customer < ActiveRecord::Base 89 | composed_of :address, :mapping => [ %w(address_street street), 90 | %w(address_city city)] 91 | end 92 | 93 | class Address 94 | attr_reader :street 95 | def initialize(street) 96 | @street, @city = street, city 97 | end 98 | 99 | def close_to?(other_address) 100 | city = other_address.city 101 | end 102 | end 103 |104 | 105 |118 |123 | ### Good Smell 124 |119 | class PostComment < ActiveRecord::Base 120 | class PhotoCommenct < ActiveRecord::Base 121 |122 |125 |139 | 140 | !SLIDE 141 | 142 | ## column 超過 10 個請注意 143 | 144 | !SLIDE 145 | 146 | ## Virtual Attribute 147 | 148 |126 | class Comment < ActiveRecord::Base 127 | belongs_to :commentable, :polymorphic => true 128 | end 129 | 130 | class Article < ActiveRecord::Base 131 | has_many :comments, :as => :commentable 132 | end 133 | 134 | class Photo < ActiveRecord::Base 135 | has_many :comments, :as => :commentable 136 | end 137 |138 |149 |164 | 165 | ### (用 getter / setter 造出 virtual attribute) 166 | 167 | !SLIDE 168 | 169 | ## Serialize 170 | 171 |150 | 151 | <%= f.text_field :full_name %> 152 | 153 | def full_name 154 | [first_name, last_name].join(' ') 155 | end 156 | 157 | def full_name=(name) 158 | split = name.split(' ', 2) 159 | self.first_name = split.first 160 | self.last_name = split.last 161 | end 162 |163 |172 |183 | 184 | ### (把小資料存在同一個 column 內) -------------------------------------------------------------------------------- /organize/2_controller.md: -------------------------------------------------------------------------------- 1 | !SLIDE 2 | 3 | ### 類似的 code 在同一個 controller 出現第3次請注意 4 | 5 | !SLIDE code 6 | 7 | ## 使用 before_filter 整理 8 | 9 |173 | class User < ActiveRecord::Base 174 | serialize :preferences 175 | end 176 | 177 | user = User.create(:preferences => { "background" => "black", 178 | "display" => large }) 179 | User.find(user.id).preferences # => { "background" => "black", 180 | "display" => large } 181 |182 |10 |30 | 31 | !SLIDE 32 | 33 | ### 相同的 method 在不同 controller 出現第二次出現請注意 34 | 35 | !SLIDE 36 | 37 | ## 搬到 application controller 38 | 39 |11 | class PostController < ApplicationController 12 | before_filter :find_category 13 | 14 | def show 15 | # xxxx 16 | end 17 | 18 | def edit 19 | # xxxx 20 | end 21 | 22 | protected 23 | 24 | def find_category 25 | @category = Category.find(params[:category_id]) 26 | end 27 | end 28 |29 |40 |56 | 57 | !SLIDE 58 | 59 | ### 類似形式的 controller 出現第二次請注意 60 | 61 | !SLIDE 62 | 63 | ## 使用 NameSpace 整理 controller 64 | 65 | ### BAD SMELL 66 | 67 | app/controller/user_favorites_controller.rb 68 |41 | class ApplicationController < ActionController::Base 42 | def find_user 43 | @user = current_user 44 | end 45 | end 46 | 47 | class UserFavoritesController < ApplicationController 48 | before_filter :find_user 49 | end 50 | 51 | class UserProfileController < ApplicationController 52 | before_filter :find_user 53 | end 54 |55 |69 |76 | 77 | ### GOOD SMELL 78 | app/controller/user/favorites_controller.rb 79 |70 | class UserFavoritesController < ApplicationController 71 | 72 | class UserProfileController < ApplicationController 73 | 74 |75 |80 |87 | 88 | !SLIDE 89 | 90 | ## 單一 method 超過 15 行請注意 91 | 92 | !SLIDE bullets left 93 | 94 | ## Refactor 95 | 96 | * refactor 到 model 97 | - 「業務邏輯相關的資料」 98 | - 「對資料的處理方法」 99 | * refactor to presentor 100 | - 不是什麼都需要扔 model 101 | - Model - View - Presenter 102 | 103 | !SLIDE 104 | 105 | # MVP 106 | ### Model - View - Presenter 107 | 108 | !SLIDE bullets left 109 | 110 | ## MVP 111 | 112 | * UI 高度依賴業務邏輯 113 | * 業務過於複雜 114 | * 僅在該 View 使用一次,且不屬於 Model 的基礎 method 115 | * 不應該放在 Controller / Model,而應該放在 Presenter 116 | * 業務邏輯抽出來放在 Presenter,可以隨意改動 UI 117 | 118 | !SLIDE smallest 119 | 120 | # Presenter 121 | 122 |81 | class User::FavoritesController < ApplicationController 82 | 83 | class User::ProfileController < ApplicationController 84 | 85 |86 |123 |137 | 138 | !SLIDE smallest 139 | 140 | # Use presenter in controller 141 |124 | class Sites::ShowPresenter 125 | 126 | def hottest_topics 127 | @hottest_topics = @site.topics.hottest.limit(10) 128 | end 129 | 130 | def recent_topics 131 | @recent_topics = @site.topics.unhidden.recent(10) 132 | end 133 | 134 | end 135 |136 |142 |154 | 155 | !SLIDE 156 | 157 | ## 儲存之前、儲存之後需要 do something 158 | 159 | !SLIDE code 160 | 161 | ## BAD SMELL 162 | 163 |143 | def show 144 | @presenter = Sites::ShowPresenter.new(@site) 145 | @headline_topic = @presenter.headline_topic 146 | @categories = @presenter.categories 147 | @site_alias = @presenter.site_alias 148 | 149 | add_breadcrumb @site.name, site_path(@site) 150 | seo_meta_desc_keywords(@site) 151 | end 152 |153 |164 |170 | 171 | !SLIDE code 172 | 173 | ## 善用 model callbacks 174 |165 | if @post.save 166 | @post.delay.update_search_index 167 | end 168 |169 |175 |181 | 182 | ## 或者是 Observer 183 | 184 |176 | class Post < ActiveRecord::Base 177 | after_save :update_search_index 178 | end 179 |180 |185 |-------------------------------------------------------------------------------- /bad_code/bad_code.md: -------------------------------------------------------------------------------- 1 | !SLIDE bullets incremental left 2 | 3 | ## 為什麼 Code 這麼容易腐敗? 4 | 5 | !SLIDE 6 | 7 | ##186 | class PostObserver < ActiveRecord::Observer 187 | observ :post 188 | 189 | def after_save(post) 190 | update_search_index 191 | end 192 | end 193 |194 |其實大多數 Rails Developer 不會寫 Rails8 | 9 | !SLIDE bullets left 10 | 11 | # 常見的 Rails Code 12 | 13 | * 晦澀:難以閱讀,無法了解意圖 14 | * 不需要的重複:相同概念的程式碼被複製貼上重複使用 15 | * 黏滯:彈性不夠,把事情做對比做錯還難 16 | * 固定: 難以分解,讓程式再重用 17 | * 脆弱: 一旦修改,別的無關地方也炸到 18 | * 僵硬 : 難以修改,每改一處牽一髮動全身 19 | 20 | !SLIDE center 21 | 22 | # Spaghetti code 23 | 24 |25 |27 | 28 | !SLIDE bullets left 29 | 30 | # Spaghetti code 的成因 31 | 32 | * Don't know how to code 33 | * IT JUST WORKS! 34 | * PHP, .NET, JAVA coding tyle 35 | * unfamiliar with Rails way 36 | 37 | !SLIDE bullets xleft 38 | 39 | # Common Antipatterns 40 | 41 | * 不好的程式寫作習慣 42 | * 不適當的 Coding Style 43 | * 隨意亂扔程式碼 44 | * 到處複製貼上程式碼 45 | * 濫用 Framework / ORM 46 | * 重複發明輪子 47 | 48 | 49 | !SLIDE 50 | 51 | # 使用大量的縮寫 52 | ## 不好的寫作習慣 53 | 54 | !SLIDE code left 55 | 56 | ### 無法理解 57 | 58 |26 |
59 |65 | 66 | ### 容易理解 67 | 68 |60 | def t_tags 61 | t_list.join(" ") 62 | end 63 |64 |69 |75 | 76 | !SLIDE 77 | 78 | # 能夠不縮寫就不縮寫 79 | ### 真的太長的 method name ( 3個詞以上),使用 module 或 namespace 80 | 81 | !SLIDE code left 82 | 83 | # 無法了解意義的變數 84 | 85 | ## 錯誤 86 | 87 |70 | def tokenized_tags 71 | tag_list.join(" ") 72 | end 73 |74 |88 |102 | 103 | !SLIDE code left 104 | 105 | ## 正確 106 | 107 |89 | case game_type 90 | 91 | when "1" 92 | # do_something_x 93 | when "2" 94 | # do_something_y 95 | when "3" 96 | # do_something_z 97 | else 98 | # redirect_to root_path 99 | end 100 |101 |108 |121 | 122 | !SLIDE 123 | 124 | # 濫用 elsif 125 | ## 不好的寫作習慣 126 | 127 | !SLIDE code 128 | 129 | ## 邏輯混亂 130 | 131 |109 | case game_type 110 | when "rpg" 111 | # do_somehting_x 112 | when "strategy" 113 | # do_something_y 114 | when "fps" 115 | # do_something_y 116 | else 117 | # redirect_to root_path 118 | end 119 |120 |132 |144 | 145 | !SLIDE code 146 | 147 | ## 容易理解 148 | 149 |133 | if color=="red" 134 | print "red" 135 | elsif color="green" 136 | print "green" 137 | elsif orignal_color=="yellow" 138 | print "yellow" 139 | else 140 | print "orange" 141 | end 142 |143 |150 |167 | 168 | !SLIDE 169 | 170 | # 語意不明 171 | ## 不好的寫作習慣 172 | 173 | !SLIDE code 174 | 175 | ## 動詞 / 名詞 / 形容詞 傻傻搞不清楚 176 | 177 | ### 錯誤 178 | 179 |151 | if original_color == "yellow" 152 | print "yellow" 153 | return 154 | end 155 | 156 | case color 157 | when "red" 158 | print "red" 159 | when "green" 160 | print "green" 161 | else 162 | print "orange" 163 | end 164 | 165 |166 |180 |184 | 185 | ### 正確 186 | 187 |181 | post.is_hide 182 |183 |188 |192 | 193 | !SLIDE code 194 | 195 | ## 是不是 spam ? => 疑問,回傳 true / false 196 | 197 |189 | post.is_hidden 190 |191 |198 |202 | 203 | ## 標記為 spam! => bang,改變狀態 204 | 205 |199 | post.is_spam? 200 |201 |206 |210 | 211 | !SLIDE 212 | 213 | # 濫用自創名詞 214 | ## 不好的寫作習慣 215 | 216 | !SLIDE code 217 | 218 | ## 攻 / 受 ( 錯誤示範 ) 219 | 220 |207 | post.is_spam! 208 |209 |221 |225 | 226 | ## 傳送者 / 接收者 ( 正確示範 ) 227 | 228 |222 | attacker / defender 223 |224 |229 |233 | 234 | !SLIDE 235 | 236 | ## 類似的 method,變數與寫法不一致 237 | ### 不好的寫作習慣 238 | 239 | !SLIDE center 240 | 241 | ### 一下使用 block, 一下使用 lambda 242 | 243 |230 | sender / reciever 231 |232 |244 | 245 |
246 | 247 | ### 類似的 method,寫法不一致 248 | 249 |250 | 251 | !SLIDE 252 | 253 | # 不適當的 Coding Style 254 | 255 | !SLIDE center 256 | 257 | ## 不一致的縮排 258 | 259 |
260 | 261 | !SLIDE center 262 | 263 | ## method 使用 CamelCase 264 | 265 |
266 | 267 | !SLIDE center 268 | 269 | ## more on... 270 | 271 |
272 | 273 |
274 | ## The Book of Weird Ruby 275 | ### 擁有各式各樣奇怪的 Ruby 範例 276 | 277 | !SLIDE bullets incremental left 278 | 279 | ## 正確的 Ruby Coding Style 280 | 281 | * Use 2 space indent, no tabs. 282 | * Use snake_case for methods. 283 | * Use CamelCase for classes and modules. 284 | * Use SCREAMIN\_SNAKE\_CASE for other constants. 285 | 286 | !SLIDE bullets incremental left 287 | 288 | ## 正確的 Ruby Coding Style 289 | 290 | 291 | * 大範圍的程式碼使用 do end。1-2 行使用 lambda {} 292 | * 定義 method 要加括號 ()。除非是宣告或 command 293 | - 加括號:hello(name) # 一般 method 294 | - 可不加括號: attr_accessible :nickname # 宣告或 command 295 | 296 | !SLIDE center 297 | 298 | ## more on... 299 | 300 |301 | 302 |
303 | ## Eloquent Ruby 304 | ### 學習寫正確的 Ruby code 305 | 306 | !SLIDE 307 | 308 | ### 如果你的 code 不直觀的話,你不是在寫 Ruby code 309 | 310 | !SLIDE 311 | 312 | ### 道德底線: Readability ( 易讀,容易了解 ) 313 | -------------------------------------------------------------------------------- /compass_app_log.txt: -------------------------------------------------------------------------------- 1 | 2011-08-23 02:50:43 overwrite stylesheets/rubyconftw.css 2 | 2011-08-23 02:50:56 identical stylesheets/rubyconftw.css 3 | 2011-08-23 02:51:00 identical stylesheets/rubyconftw.css 4 | 2011-08-23 02:51:10 identical stylesheets/rubyconftw.css 5 | 2011-08-23 02:52:40 identical stylesheets/rubyconftw.css 6 | 2011-08-23 02:53:05 identical stylesheets/rubyconftw.css 7 | 2011-08-23 02:53:28 overwrite stylesheets/rubyconftw.css 8 | 2011-08-23 02:53:34 overwrite stylesheets/rubyconftw.css 9 | 2011-08-23 02:56:13 overwrite stylesheets/rubyconftw.css 10 | 2011-08-23 02:56:23 overwrite stylesheets/rubyconftw.css 11 | 2011-08-23 02:56:28 overwrite stylesheets/rubyconftw.css 12 | 2011-08-23 02:56:31 overwrite stylesheets/rubyconftw.css 13 | 2011-08-23 02:57:00 identical stylesheets/rubyconftw.css 14 | 2011-08-23 02:57:01 identical stylesheets/rubyconftw.css 15 | 2011-08-23 02:58:15 overwrite stylesheets/rubyconftw.css 16 | 2011-08-23 02:58:19 overwrite stylesheets/rubyconftw.css 17 | 2011-08-23 02:59:06 overwrite stylesheets/rubyconftw.css 18 | 2011-08-23 03:01:32 overwrite stylesheets/rubyconftw.css 19 | 2011-08-23 03:01:47 overwrite stylesheets/rubyconftw.css 20 | 2011-08-23 03:02:19 overwrite stylesheets/rubyconftw.css 21 | 2011-08-23 03:02:22 overwrite stylesheets/rubyconftw.css 22 | 2011-08-23 03:04:32 overwrite stylesheets/rubyconftw.css 23 | 2011-08-23 03:04:49 overwrite stylesheets/rubyconftw.css 24 | 2011-08-23 03:06:34 overwrite stylesheets/rubyconftw.css 25 | 2011-08-23 03:10:05 overwrite stylesheets/rubyconftw.css 26 | 2011-08-23 03:10:12 overwrite stylesheets/rubyconftw.css 27 | 2011-08-23 03:10:18 overwrite stylesheets/rubyconftw.css 28 | 2011-08-23 03:10:35 overwrite stylesheets/rubyconftw.css 29 | 2011-08-23 03:10:59 overwrite stylesheets/rubyconftw.css 30 | 2011-08-23 03:11:03 overwrite stylesheets/rubyconftw.css 31 | 2011-08-23 03:11:17 overwrite stylesheets/rubyconftw.css 32 | 2011-08-23 03:11:31 overwrite stylesheets/rubyconftw.css 33 | 2011-08-23 03:11:57 overwrite stylesheets/rubyconftw.css 34 | 2011-08-23 03:12:02 overwrite stylesheets/rubyconftw.css 35 | 2011-08-23 03:12:21 overwrite stylesheets/rubyconftw.css 36 | 2011-08-23 03:12:56 overwrite stylesheets/rubyconftw.css 37 | 2011-08-23 03:13:00 overwrite stylesheets/rubyconftw.css 38 | 2011-08-23 03:13:32 overwrite stylesheets/rubyconftw.css 39 | 2011-08-23 03:15:28 overwrite stylesheets/rubyconftw.css 40 | 2011-08-23 03:23:31 overwrite stylesheets/rubyconftw.css 41 | 2011-08-23 03:23:35 overwrite stylesheets/rubyconftw.css 42 | 2011-08-23 03:23:43 overwrite stylesheets/rubyconftw.css 43 | 2011-08-23 03:24:09 overwrite stylesheets/rubyconftw.css 44 | 2011-08-23 03:24:34 overwrite stylesheets/rubyconftw.css 45 | 2011-08-23 03:24:41 error sass/rubyconftw.scss (Line 9: Invalid CSS after "...xt align:center": expected "{", was ";}") 46 | 2011-08-23 03:24:41 overwrite stylesheets/rubyconftw.css 47 | 2011-08-23 03:24:50 overwrite stylesheets/rubyconftw.css 48 | 2011-08-23 03:24:56 overwrite stylesheets/rubyconftw.css 49 | 2011-08-23 03:25:04 overwrite stylesheets/rubyconftw.css 50 | 2011-08-23 03:29:28 overwrite stylesheets/rubyconftw.css 51 | 2011-08-23 03:29:43 overwrite stylesheets/rubyconftw.css 52 | 2011-08-23 03:29:51 overwrite stylesheets/rubyconftw.css 53 | 2011-08-23 03:30:03 overwrite stylesheets/rubyconftw.css 54 | 2011-08-23 03:30:08 overwrite stylesheets/rubyconftw.css 55 | 2011-08-23 03:30:21 overwrite stylesheets/rubyconftw.css 56 | 2011-08-23 03:31:39 overwrite stylesheets/rubyconftw.css 57 | 2011-08-23 03:31:58 overwrite stylesheets/rubyconftw.css 58 | 2011-08-23 03:32:11 overwrite stylesheets/rubyconftw.css 59 | 2011-08-23 03:32:56 error sass/rubyconftw.scss (Line 28: Invalid CSS after "}": expected selector or at-rule, was "{list-style-typ...") 60 | 2011-08-23 03:32:56 overwrite stylesheets/rubyconftw.css 61 | 2011-08-23 03:33:02 overwrite stylesheets/rubyconftw.css 62 | 2011-08-23 03:37:46 overwrite stylesheets/rubyconftw.css 63 | 2011-08-23 03:40:01 overwrite stylesheets/rubyconftw.css 64 | 2011-08-23 03:40:13 error sass/rubyconftw.scss (Line 23: Invalid CSS after "...0px 40px; lin ": expected "{", was "}") 65 | 2011-08-23 03:40:13 overwrite stylesheets/rubyconftw.css 66 | 2011-08-23 03:40:20 overwrite stylesheets/rubyconftw.css 67 | 2011-08-23 03:40:33 overwrite stylesheets/rubyconftw.css 68 | 2011-08-23 03:40:37 overwrite stylesheets/rubyconftw.css 69 | 2011-08-23 03:40:42 overwrite stylesheets/rubyconftw.css 70 | 2011-08-23 03:40:52 overwrite stylesheets/rubyconftw.css 71 | 2011-08-23 03:41:04 overwrite stylesheets/rubyconftw.css 72 | 2011-08-23 03:41:37 overwrite stylesheets/rubyconftw.css 73 | 2011-08-23 03:41:41 overwrite stylesheets/rubyconftw.css 74 | 2011-08-23 03:42:33 overwrite stylesheets/rubyconftw.css 75 | 2011-08-23 03:42:41 overwrite stylesheets/rubyconftw.css 76 | 2011-08-23 03:42:46 identical stylesheets/rubyconftw.css 77 | 2011-08-23 03:46:16 overwrite stylesheets/rubyconftw.css 78 | 2011-08-23 03:46:22 overwrite stylesheets/rubyconftw.css 79 | 2011-08-23 03:48:18 overwrite stylesheets/rubyconftw.css 80 | 2011-08-23 03:48:38 overwrite stylesheets/rubyconftw.css 81 | 2011-08-23 03:48:42 overwrite stylesheets/rubyconftw.css 82 | 2011-08-23 03:48:58 overwrite stylesheets/rubyconftw.css 83 | 2011-08-23 03:49:04 overwrite stylesheets/rubyconftw.css 84 | 2011-08-23 03:49:08 overwrite stylesheets/rubyconftw.css 85 | 2011-08-23 03:49:18 overwrite stylesheets/rubyconftw.css 86 | 2011-08-23 03:49:28 overwrite stylesheets/rubyconftw.css 87 | 2011-08-23 03:49:40 overwrite stylesheets/rubyconftw.css 88 | 2011-08-23 03:49:42 overwrite stylesheets/rubyconftw.css 89 | 2011-08-23 03:49:46 overwrite stylesheets/rubyconftw.css 90 | 2011-08-23 03:50:03 overwrite stylesheets/rubyconftw.css 91 | 2011-08-23 03:50:15 overwrite stylesheets/rubyconftw.css 92 | 2011-08-23 03:50:20 overwrite stylesheets/rubyconftw.css 93 | 2011-08-23 04:00:16 overwrite stylesheets/rubyconftw.css 94 | 2011-08-23 04:00:20 overwrite stylesheets/rubyconftw.css 95 | 2011-08-23 04:03:49 overwrite stylesheets/rubyconftw.css 96 | 2011-08-23 04:04:11 overwrite stylesheets/rubyconftw.css 97 | 2011-08-23 04:04:17 overwrite stylesheets/rubyconftw.css 98 | 2011-08-23 04:05:34 overwrite stylesheets/rubyconftw.css 99 | 2011-08-23 04:05:38 overwrite stylesheets/rubyconftw.css 100 | 2011-08-23 04:05:56 overwrite stylesheets/rubyconftw.css 101 | 2011-08-23 04:06:00 overwrite stylesheets/rubyconftw.css 102 | 2011-08-23 04:06:04 overwrite stylesheets/rubyconftw.css 103 | 2011-08-23 04:06:07 overwrite stylesheets/rubyconftw.css 104 | 2011-08-23 04:08:07 overwrite stylesheets/rubyconftw.css 105 | 2011-08-23 04:08:18 overwrite stylesheets/rubyconftw.css 106 | 2011-08-23 04:08:23 overwrite stylesheets/rubyconftw.css 107 | 2011-08-23 04:17:50 overwrite stylesheets/rubyconftw.css 108 | 2011-08-23 04:18:27 error sass/rubyconftw.scss (Line 41: Invalid CSS after "...g-bottom: 20px;": expected "}", was "{") 109 | 2011-08-23 04:18:27 overwrite stylesheets/rubyconftw.css 110 | 2011-08-23 04:18:31 overwrite stylesheets/rubyconftw.css 111 | 2011-08-23 04:19:32 overwrite stylesheets/rubyconftw.css 112 | 2011-08-23 04:19:35 identical stylesheets/rubyconftw.css 113 | 2011-08-23 04:19:43 overwrite stylesheets/rubyconftw.css 114 | 2011-08-23 04:20:01 overwrite stylesheets/rubyconftw.css 115 | 2011-08-23 04:20:22 overwrite stylesheets/rubyconftw.css 116 | 2011-08-23 04:20:34 overwrite stylesheets/rubyconftw.css 117 | 2011-08-23 11:22:44 overwrite stylesheets/rubyconftw.css 118 | 2011-08-23 11:22:55 overwrite stylesheets/rubyconftw.css 119 | 2011-08-23 11:23:07 overwrite stylesheets/rubyconftw.css 120 | 2011-08-23 11:42:10 overwrite stylesheets/rubyconftw.css 121 | 2011-08-23 11:42:13 identical stylesheets/rubyconftw.css 122 | 2011-08-23 11:42:25 identical stylesheets/rubyconftw.css 123 | 2011-08-23 11:42:57 overwrite stylesheets/rubyconftw.css 124 | 2011-08-23 12:01:57 overwrite stylesheets/rubyconftw.css 125 | 2011-08-23 12:02:10 identical stylesheets/rubyconftw.css 126 | 2011-08-23 12:02:19 identical stylesheets/rubyconftw.css 127 | 2011-08-23 12:02:24 overwrite stylesheets/rubyconftw.css 128 | 2011-08-23 12:21:12 overwrite stylesheets/rubyconftw.css 129 | 2011-08-23 12:21:36 overwrite stylesheets/rubyconftw.css 130 | 2011-08-23 12:22:40 overwrite stylesheets/rubyconftw.css 131 | 2011-08-23 12:23:10 overwrite stylesheets/rubyconftw.css 132 | 2011-08-23 14:28:59 error sass/rubyconftw.scss (Line 58: Invalid CSS after "}": expected "}", was "") 133 | 2011-08-23 14:28:59 overwrite stylesheets/rubyconftw.css 134 | 2011-08-23 14:29:06 error sass/rubyconftw.scss (Line 58: Invalid CSS after "}": expected "}", was "") 135 | 2011-08-23 14:29:06 identical stylesheets/rubyconftw.css 136 | 2011-08-23 14:29:16 error sass/rubyconftw.scss (Line 60: Invalid CSS after "}": expected "}", was "") 137 | 2011-08-23 14:29:16 overwrite stylesheets/rubyconftw.css 138 | 2011-08-23 14:29:54 overwrite stylesheets/rubyconftw.css 139 | 2011-08-23 14:30:33 identical stylesheets/rubyconftw.css 140 | 2011-08-23 14:31:00 overwrite stylesheets/rubyconftw.css 141 | 2011-08-23 14:31:21 identical stylesheets/rubyconftw.css 142 | 2011-08-23 14:31:30 overwrite stylesheets/rubyconftw.css 143 | --------------------------------------------------------------------------------