├── 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 | 15 | 16 | ### Lead Developer 兼 Manager 17 | 18 | 19 | -------------------------------------------------------------------------------- /advertise/3_essential_rails.md: -------------------------------------------------------------------------------- 1 | !SLIDE center 2 | 3 | 6 | 7 | 8 | ## Essential Rails Pattern for Beginner ( This Talk ) 9 | ### pre-order price $14.9 $9.99 USD 10 | ### http://bit.ly/xdite-book-3 11 | 12 | !SLIDE 13 | 14 | # Thanks for listening 15 | 16 | 17 | -------------------------------------------------------------------------------- /our_way_to_organize/06_library.md: -------------------------------------------------------------------------------- 1 | !SLIDE 2 | 3 | # Library 4 | 5 | !SLIDE bullets left code 6 | 7 | ## 打包成 Gem 8 | 9 | * SSO Library 10 | 11 |
12 |
13 |   gem "techbang-authentication", 
14 |     :git => "git@github.com:techbang/techbang-authentication.git", 
15 |     :tag => "0.1.0"
16 | 
17 |
18 | -------------------------------------------------------------------------------- /our_way_to_organize/09_cache.md: -------------------------------------------------------------------------------- 1 | !SLIDE 2 | 3 | # Cache 4 | 5 | !SLIDE bullets left 6 | 7 | # Cells 8 | 9 | * move partial to cell 10 | * query in partial is ULTRA SLOW 11 | * cell is "mini controller", you should query in controller 12 | * use cell to organize "component" 13 | 14 | !SLIDE 15 | 16 |
17 | 18 |
-------------------------------------------------------------------------------- /our_way_to_organize/04_helper.md: -------------------------------------------------------------------------------- 1 | !SLIDE 2 | 3 | # Helper 4 | 5 | !SLIDE bullets left 6 | 7 | * by controller 8 | - post_helper 9 | - tag_helper 10 | - user_helper 11 | * extract common helper to module 12 | 13 |
14 |
15 |      helper HandicraftHelper
16 |      helper TechbangHelper
17 |   
18 |
19 | 20 | 21 | -------------------------------------------------------------------------------- /showoff.json: -------------------------------------------------------------------------------- 1 | [ 2 | {"section":"title"}, 3 | {"section":"about_me"}, 4 | {"section":"agenda"}, 5 | {"section":"bad_code"}, 6 | {"section":"mvc"}, 7 | {"section":"abusing_rails"}, 8 | {"section":"reinvent_wheels"}, 9 | {"section":"organize"}, 10 | {"section":"our_way_to_organize"}, 11 | {"section":"conclusion"}, 12 | {"section":"reference"}, 13 | {"section":"the_end"}, 14 | {"section":"advertise"} 15 | ] 16 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | specs: 3 | bluecloth (2.1.0) 4 | gli (1.3.2) 5 | json (1.5.3) 6 | nokogiri (1.5.0) 7 | rack (1.3.0) 8 | showoff (0.4.2) 9 | bluecloth 10 | gli (>= 1.2.5) 11 | json 12 | nokogiri 13 | sinatra 14 | sinatra (1.2.3) 15 | rack (~> 1.1) 16 | tilt (>= 1.2.2, < 2.0) 17 | tilt (1.3.2) 18 | 19 | PLATFORMS 20 | ruby 21 | 22 | DEPENDENCIES 23 | showoff 24 | -------------------------------------------------------------------------------- /.sass-cache/3bda273ae1167db8c681ac4d0c35b65945d2d032/_reset.scssc: -------------------------------------------------------------------------------- 1 | 3.1.7 (Brainy Betty) 2 | df78759f0fe6b88a633d20d26581ca4cdb829111 3 | o:Sass::Tree::RootNode 4 | :@template"8@import "reset/utilities"; 5 | 6 | @include global-reset; 7 | : @options{: 8 | @linei:@children[o:Sass::Tree::ImportNode 9 | ;0:@imported_filename"reset/utilities;@;i; [o:Sass::Tree::MixinNode : 10 | @args[: 11 | @name"global-reset;@;i; [:@keywords{:@has_childrenT -------------------------------------------------------------------------------- /.sass-cache/724a8e4f1c9bf41ba998c29a69300352d4dc2833/_reset.scssc: -------------------------------------------------------------------------------- 1 | 3.1.4 (Brainy Betty) 2 | df78759f0fe6b88a633d20d26581ca4cdb829111 3 | o:Sass::Tree::RootNode 4 | : 5 | @linei: @options{:@template"8@import "reset/utilities"; 6 | 7 | @include global-reset; 8 | :@has_childrenT:@children[o:Sass::Tree::ImportNode 9 | ;i;@;0:@imported_filename"reset/utilities; 10 | [o:Sass::Tree::MixinNode : 11 | @args[;i: 12 | @name"global-reset;@; 13 | [:@keywords{ -------------------------------------------------------------------------------- /conclusion/conclusion.md: -------------------------------------------------------------------------------- 1 | !SLIDE 2 | 3 | # 結語 4 | 5 | !SLIDE bullets left 6 | 7 | ## What's GOOD code? 8 | 9 | * Readbility 易讀,容易了解 10 | * Flexibilty 彈性,容易擴充 11 | * Effective 效率,撰碼快速 12 | * Maintainbility 維護性,容易找到問題 13 | * Consistency 一致性,循慣例無需死背 14 | * Testability 可測性,元件獨立容易測試 15 | 16 | !SLIDE bullets left 17 | 18 | ## How to write GOOD Rails code? 19 | 20 | * Learn Ruby 21 | - Learn Ruby before calling yourself a Rails developer 22 | * Follow Rails convention 23 | * Knowing Rails internal 24 | * Write readable code 25 | * Refactor to maintainable code all the time 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /organize/5_meta_programming.md: -------------------------------------------------------------------------------- 1 | !SLIDE 2 | 3 | ### 名稱類似、作用也類似的 method 在同一 class 出現三次請注意 4 | 5 | !SLIDE bullets left 6 | 7 | # Meta Programming 8 | 9 | * define_method 10 | 11 |
12 |
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 |
20 | 21 | * method_missing 22 | 23 |
24 |
25 |     find_by_post_id_and_user_id
26 |     find_or_initialize_by_ooo_and_xxx
27 |   
28 | -------------------------------------------------------------------------------- /reinvent_wheels/reinvent_wheels.md: -------------------------------------------------------------------------------- 1 | !SLIDE 2 | 3 | # 重複發明輪子 4 | ## 冗餘程式碼的另一個原因 5 | 6 | !SLIDE bullets left smaller 7 | 8 | ## 常用但你可能不知道的 helper 9 | 10 | * auto_link 11 | - auto link url 12 | * content_tag 13 | - content(:div, "hello world") 14 | * truncate 15 | - \# "Ruby Conf Tai...." 16 | * simple_format 17 | - convert \n to <br> / <p> 18 | 19 | !SLIDE bullets left smaller 20 | 21 | ## 常用但你可能不知道的 helper 22 | 23 | * cycle 24 | - cycle("even", "odd") 25 | * localize 26 | - l(post.published_at, :format => :long) 27 | 28 | ## /actionpack-x.y.z/action_view/helpers/* 29 | -------------------------------------------------------------------------------- /our_way_to_organize/10_expensive_jobs.md: -------------------------------------------------------------------------------- 1 | !SLIDE 2 | 3 | # Expensive Job 4 | 5 | !SLIDE bullets left 6 | 7 | ## Expensive Jobs 8 | 9 | * sending massive newsletters 10 | * image resizing 11 | * http downloads 12 | * updating solr, our search server, after product changes 13 | * batch imports 14 | * spam checks 15 | 16 | !SLIDE code 17 | 18 | ## DelayedJob 19 | 20 |
21 |
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 |
-------------------------------------------------------------------------------- /our_way_to_organize/08_settings.md: -------------------------------------------------------------------------------- 1 | !SLIDE 2 | 3 | # Settings 4 | 5 | !SLIDE 6 | 7 | ## Don't throw anything to model's constant !! 8 | 9 |


10 | 11 | ## Use yml settings or memorize method instead 12 | 13 | !SLIDE 14 | 15 | # SettingsLogic 16 | 17 |
18 |
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 |
-------------------------------------------------------------------------------- /our_way_to_organize/07_permission.md: -------------------------------------------------------------------------------- 1 | !SLIDE 2 | 3 | # Permission 4 | 5 | !SLIDE 6 | 7 | # CanCan 8 | 9 | app/model/ability.rb 10 |
11 |
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 |
-------------------------------------------------------------------------------- /organize/6_routing.md: -------------------------------------------------------------------------------- 1 | !SLIDE 2 | 3 | ## CRUD-LIKE action 4 | 5 | !SLIDE 6 | 7 | ## BAD SMELL 8 | 9 |
10 |
11 |     class UsersController < ApplicationController
12 |       def add_friend
13 |         # ....
14 |       end
15 |       
16 |       def add_to_favorites
17 |         # ....
18 |       end
19 |     end
20 |   
21 |
22 | 23 | !SLIDE 24 | 25 | ## GOOD SMELL 26 | 27 |
28 |
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 |
43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /our_way_to_organize/11_crontab.md: -------------------------------------------------------------------------------- 1 | !SLIDE 2 | 3 | # Crontab 4 | 5 | !SLIDE bullets left smaller 6 | 7 | ## whenever 8 | 9 | * crontab should with projects, not with machines 10 | 11 |
12 |
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 |
-------------------------------------------------------------------------------- /.sass-cache/07c439246232fad564fe89c3b8e897fb229dfd19/ie.scssc: -------------------------------------------------------------------------------- 1 | 3.1.7 (Brainy Betty) 2 | 55d03cbe8dc4482082815585822d80503557fdcb 3 | o:Sass::Tree::RootNode 4 | :@template"/* Welcome to Compass. Use this file to write IE specific override styles. 5 | * Import this file using the following HTML or equivalent: 6 | * */ 9 | : @options{: 10 | @linei:@children[o:Sass::Tree::CommentNode : 11 | @loud0: @value"/* Welcome to Compass. Use this file to write IE specific override styles. 12 | * Import this file using the following HTML or equivalent: 13 | * */;@;i; [: @silent0: @lines[:@has_childrenT -------------------------------------------------------------------------------- /config.rb: -------------------------------------------------------------------------------- 1 | # Require any additional compass plugins here. 2 | 3 | # Set this to the root of your project when deployed: 4 | http_path = "/" 5 | css_dir = "stylesheets" 6 | sass_dir = "sass" 7 | images_dir = "images" 8 | javascripts_dir = "javascripts" 9 | 10 | # You can select your preferred output style here (can be overridden via the command line): 11 | # output_style = :expanded or :nested or :compact or :compressed 12 | 13 | # To enable relative paths to assets via compass helper functions. Uncomment: 14 | # relative_assets = true 15 | 16 | # To disable debugging comments that display the original location of your selectors. Uncomment: 17 | # line_comments = false 18 | 19 | 20 | # If you prefer the indented syntax, you might want to regenerate this 21 | # project again passing --syntax sass, or you can uncomment this: 22 | # preferred_syntax = :sass 23 | # and then run: 24 | # sass-convert -R --from scss --to sass sass scss && rm -rf sass && mv scss sass 25 | -------------------------------------------------------------------------------- /.sass-cache/07c439246232fad564fe89c3b8e897fb229dfd19/screen.scssc: -------------------------------------------------------------------------------- 1 | 3.1.7 (Brainy Betty) 2 | e24c39d4800ce9f9b6b50e6a9d2d8c3fce9d548f 3 | o:Sass::Tree::RootNode 4 | :@template"'/* Welcome to Compass. 5 | * In this file you should write your main styles. (or centralize your imports) 6 | * Import this file using the following HTML or equivalent: 7 | * */ 8 | 9 | @import "compass/reset"; 10 | : @options{: 11 | @linei:@children[o:Sass::Tree::CommentNode : 12 | @loud0: @value" /* Welcome to Compass. 13 | * In this file you should write your main styles. (or centralize your imports) 14 | * Import this file using the following HTML or equivalent: 15 | * */;@;i; [: @silent0: @lines[o:Sass::Tree::ImportNode 16 | ;0:@imported_filename"compass/reset;@;i ; [:@has_childrenT -------------------------------------------------------------------------------- /sass/rubyconftw.scss: -------------------------------------------------------------------------------- 1 | body, #preso, .slide { 2 | // background-color: rgb(0,47,73); 3 | background-color: black; 4 | color: white; 5 | border: none; 6 | } 7 | 8 | .left { 9 | text-align: left; 10 | } 11 | 12 | .left.bullets ul li{ 13 | text-align: left; 14 | } 15 | 16 | #spaghetti{ 17 | margin-top: 30px; 18 | img{ 19 | width: 350px; 20 | height: 350px; 21 | } 22 | } 23 | 24 | .bullets{ 25 | li { font-size: 36px; padding: 10px 20px 10px 40px; line-height: 1.2em; } 26 | li:before { content: url("/image/ruby.png"); padding: 10px 20px 10px 10px; } 27 | li ul { padding-top: 20px;} 28 | li li { font-size: 24px; padding: 10px;} 29 | li li:before { content: ''; } 30 | pre + h2 { padding-top: 36px; } 31 | } 32 | 33 | .correct{ 34 | color: green; 35 | } 36 | 37 | .wrong{ 38 | color: red; 39 | } 40 | 41 | span.filename{ 42 | font-size: 1.1em; 43 | padding: 10px 0px 20px 40px ; 44 | display: block; 45 | } 46 | 47 | .code{ 48 | pre{ 49 | font-size: 2em; 50 | line-height: 1.5em; 51 | } 52 | } 53 | 54 | .smallest{ 55 | font-size: 60%; 56 | } 57 | 58 | div.image{ 59 | text-align:center; 60 | } 61 | -------------------------------------------------------------------------------- /our_way_to_organize/02_view.md: -------------------------------------------------------------------------------- 1 | !SLIDE 2 | 3 | # View 4 | 5 | !SLIDE code 6 | 7 |
8 |
 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 |
21 | 22 | !SLIDE code 23 |
24 |
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 |
42 | 43 | !SLIDE code 44 |
45 |
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 |
58 | 59 | !SLIDE 60 | 61 | ## functional partial 62 | 63 | !SLIDE bullets left 64 | 65 | * app/views/common 66 | * app/views/sidebar 67 | * app/views/advertises 68 | -------------------------------------------------------------------------------- /organize/1_view.md: -------------------------------------------------------------------------------- 1 | !SLIDE 2 | 3 | # View 4 | ## 超過 2.5 頁請注意 5 | 6 | !SLIDE 7 | 8 | ## 常用的 html 使用 partial 整理 9 | 10 |
11 |
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 |
31 | 32 | ### (全站 HEADER) 33 | 34 | !SLIDE code 35 | 36 | ## 重複用到的 html 使用 partial 整理 37 | 38 |
39 |
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 |
51 | 52 | ### (文章列表) 53 | 54 | !SLIDE 55 | 56 | # View 57 | 58 | ## 同樣用途的 helper 出現第三次請注意 59 | 60 | !SLIDE code 61 | 62 | ## BAD SMELL 63 |
64 |
65 |     <span>發表於 <%=  l(@post.published_at, :format => :long) %></span>
66 |   
67 |
68 | 69 | ## GOOD SMELL 70 | 71 |
72 |
73 |      <span>發表於 <%= render_published_at(@post) %></span>
74 |   
75 |
76 | -------------------------------------------------------------------------------- /rubyconftw.css: -------------------------------------------------------------------------------- 1 | /* line 1, ../sass/rubyconftw.scss */ 2 | body, #preso, .slide { 3 | background-color: black; 4 | color: white; 5 | border: none; 6 | } 7 | 8 | /* line 8, ../sass/rubyconftw.scss */ 9 | .left { 10 | text-align: left; 11 | } 12 | 13 | /* line 12, ../sass/rubyconftw.scss */ 14 | .left.bullets ul li { 15 | text-align: left; 16 | } 17 | 18 | /* line 16, ../sass/rubyconftw.scss */ 19 | #spaghetti { 20 | margin-top: 30px; 21 | } 22 | /* line 18, ../sass/rubyconftw.scss */ 23 | #spaghetti img { 24 | width: 350px; 25 | height: 350px; 26 | } 27 | 28 | /* line 25, ../sass/rubyconftw.scss */ 29 | .bullets li { 30 | font-size: 36px; 31 | padding: 10px 20px 10px 40px; 32 | line-height: 1.2em; 33 | } 34 | /* line 26, ../sass/rubyconftw.scss */ 35 | .bullets li:before { 36 | content: url("/image/ruby.png"); 37 | padding: 10px 20px 10px 10px; 38 | } 39 | /* line 27, ../sass/rubyconftw.scss */ 40 | .bullets li ul { 41 | padding-top: 20px; 42 | } 43 | /* line 28, ../sass/rubyconftw.scss */ 44 | .bullets li li { 45 | font-size: 24px; 46 | padding: 10px; 47 | } 48 | /* line 29, ../sass/rubyconftw.scss */ 49 | .bullets li li:before { 50 | content: ''; 51 | } 52 | /* line 30, ../sass/rubyconftw.scss */ 53 | .bullets pre + h2 { 54 | padding-top: 36px; 55 | } 56 | 57 | /* line 33, ../sass/rubyconftw.scss */ 58 | .correct { 59 | color: #00FF00; 60 | } 61 | 62 | /* line 37, ../sass/rubyconftw.scss */ 63 | .wrong { 64 | color: #FF0000; 65 | } 66 | 67 | /* line 41, ../sass/rubyconftw.scss */ 68 | span.filename { 69 | font-size: 1.1em; 70 | padding: 10px 0px 20px 40px; 71 | display: block; 72 | } 73 | 74 | /* line 48, ../sass/rubyconftw.scss */ 75 | .code pre { 76 | font-size: 2em; 77 | line-height: 1.5em; 78 | } 79 | 80 | /* line 54, ../sass/rubyconftw.scss */ 81 | .smallest { 82 | font-size: 60%; 83 | } 84 | 85 | /* line 58, ../sass/rubyconftw.scss */ 86 | div.image { 87 | text-align: center; 88 | } 89 | -------------------------------------------------------------------------------- /stylesheets/rubyconftw.css: -------------------------------------------------------------------------------- 1 | /* line 1, ../sass/rubyconftw.scss */ 2 | body, #preso, .slide { 3 | background-color: black; 4 | color: white; 5 | border: none; 6 | } 7 | 8 | /* line 8, ../sass/rubyconftw.scss */ 9 | .left { 10 | text-align: left; 11 | } 12 | 13 | /* line 12, ../sass/rubyconftw.scss */ 14 | .left.bullets ul li { 15 | text-align: left; 16 | } 17 | 18 | /* line 16, ../sass/rubyconftw.scss */ 19 | #spaghetti { 20 | margin-top: 30px; 21 | } 22 | /* line 18, ../sass/rubyconftw.scss */ 23 | #spaghetti img { 24 | width: 350px; 25 | height: 350px; 26 | } 27 | 28 | /* line 25, ../sass/rubyconftw.scss */ 29 | .bullets li { 30 | font-size: 36px; 31 | padding: 10px 20px 10px 40px; 32 | line-height: 1.2em; 33 | } 34 | /* line 26, ../sass/rubyconftw.scss */ 35 | .bullets li:before { 36 | content: url("/image/ruby.png"); 37 | padding: 10px 20px 10px 10px; 38 | } 39 | /* line 27, ../sass/rubyconftw.scss */ 40 | .bullets li ul { 41 | padding-top: 20px; 42 | } 43 | /* line 28, ../sass/rubyconftw.scss */ 44 | .bullets li li { 45 | font-size: 24px; 46 | padding: 10px; 47 | } 48 | /* line 29, ../sass/rubyconftw.scss */ 49 | .bullets li li:before { 50 | content: ''; 51 | } 52 | /* line 30, ../sass/rubyconftw.scss */ 53 | .bullets pre + h2 { 54 | padding-top: 36px; 55 | } 56 | 57 | /* line 33, ../sass/rubyconftw.scss */ 58 | .correct { 59 | color: #00FF00; 60 | } 61 | 62 | /* line 37, ../sass/rubyconftw.scss */ 63 | .wrong { 64 | color: #FF0000; 65 | } 66 | 67 | /* line 41, ../sass/rubyconftw.scss */ 68 | span.filename { 69 | font-size: 1.1em; 70 | padding: 10px 0px 20px 40px; 71 | display: block; 72 | } 73 | 74 | /* line 48, ../sass/rubyconftw.scss */ 75 | .code pre { 76 | font-size: 2em; 77 | line-height: 1.5em; 78 | } 79 | 80 | /* line 54, ../sass/rubyconftw.scss */ 81 | .smallest { 82 | font-size: 60%; 83 | } 84 | 85 | /* line 58, ../sass/rubyconftw.scss */ 86 | div.image { 87 | text-align: center; 88 | } 89 | -------------------------------------------------------------------------------- /.sass-cache/1d8aa3db07720ffbd41ce6b7461fa25fa8bc97a4/_reset.scssc: -------------------------------------------------------------------------------- 1 | 3.0.24 (Classy Cassidy) 2 | df78759f0fe6b88a633d20d26581ca4cdb829111 3 | o:Sass::Tree::RootNode 4 | : 5 | @linei: @options{: 6 | style: expanded:load_paths[ "./public/stylesheets/sass"C/Users/xdite/Dropbox/presentation/2011-ruby-conf-tw-xdite/sass"o/Applications/compass.app/Contents/Resources/ruby/gem/gems/compass-0.10.6/frameworks/blueprint/stylesheets"~/Applications/compass.app/Contents/Resources/ruby/gem/gems/compass-0.10.6/frameworks/_blueprint_deprecated_imports/stylesheets"m/Applications/compass.app/Contents/Resources/ruby/gem/gems/compass-0.10.6/frameworks/compass/stylesheets"|/Applications/compass.app/Contents/Resources/ruby/gem/gems/compass-0.10.6/frameworks/_compass_deprecated_imports/stylesheets"l/Applications/compass.app/Contents/Resources/ruby/gem/gems/compass-960-plugin-0.10.0/lib/../stylesheets"j/Applications/compass.app/Contents/Resources/ruby/gem/gems/html5-boilerplate-0.2.6/lib/../stylesheets: 7 | cacheT:cache_location"J/Users/xdite/Dropbox/presentation/2011-ruby-conf-tw-xdite/.sass-cache: syntax: scss:full_exceptionT:css_location"./public/stylesheets:always_updateF:always_checkT:line_commentsT:template_location[ [@@[@ "J/Users/xdite/Dropbox/presentation/2011-ruby-conf-tw-xdite/stylesheets[@ 8 | "J/Users/xdite/Dropbox/presentation/2011-ruby-conf-tw-xdite/stylesheets[@ "J/Users/xdite/Dropbox/presentation/2011-ruby-conf-tw-xdite/stylesheets[@ "J/Users/xdite/Dropbox/presentation/2011-ruby-conf-tw-xdite/stylesheets[@ "J/Users/xdite/Dropbox/presentation/2011-ruby-conf-tw-xdite/stylesheets[@"J/Users/xdite/Dropbox/presentation/2011-ruby-conf-tw-xdite/stylesheets[@"J/Users/xdite/Dropbox/presentation/2011-ruby-conf-tw-xdite/stylesheets: filename"|/Applications/compass.app/Contents/Resources/ruby/gem/gems/compass-0.10.6/frameworks/compass/stylesheets/compass/_reset.scss:property_syntax0:@has_childrenT:@template"8@import "reset/utilities"; 9 | 10 | @include global-reset; 11 | :@children[o:Sass::Tree::ImportNode 12 | ;i;@;0:@imported_filename"reset/utilities;[o:Sass::Tree::MixinNode 13 | : 14 | @args[;i: 15 | @name"global-reset;@;[ -------------------------------------------------------------------------------- /mvc/mvc.md: -------------------------------------------------------------------------------- 1 | !SLIDE 2 | 3 | 4 | # Rails => MVC 5 | ## 不要隨意亂扔原始碼 6 | 7 | !SLIDE bullets incremental left 8 | 9 | # MVC 10 | 11 | * Model 12 | - 用於封裝與 「業務邏輯相關的資料」 以及 「對資料的處理方法」 13 | * Controller 14 | - 控制應用程式的流程 15 | * View 16 | - 負責資料與介面的呈現 17 | 18 | !SLIDE 19 | 20 | ## View 只負責資料的呈現 21 | ### 不要將 UI 邏輯與基礎行為混在一起 22 | 23 | !SLIDE bullets incremental left 24 | 25 | # Antipatterns 26 | 27 | * LOGIC IN VIEW 28 | * 在 Controller 裡處理資料 29 | * 在 Model 裡寫 view code 30 | 31 | !SLIDE code 32 | # LOGIC IN VIEW 33 | 34 | ### 錯誤 35 | 36 |
37 |
 38 |   <% if current_user && current_user == post.user %>
 39 |     <%= link_to("Edit", edit_post_path(post))%>
 40 |   <% end %>
 41 |   
42 |
43 | 44 | ### 正確 45 | 46 |
47 |
 48 |     <% if editable?(post) %>
 49 |       <%= link_to("Edit", edit_post_path(post))%>
 50 |     <% end %>
 51 |   
52 |
53 | 54 | 55 | !SLIDE 56 | ## 在 Controller 裡處理資料 57 | 58 | ### 錯誤 59 | 60 |
61 |
 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 |
70 | 71 | ### 正確 72 | 73 |
74 |
 75 |     def checkout
 76 |        book = Book.find(params[:id])
 77 |        current_user.purchase(book)
 78 |        redirect_to account_path
 79 |     end   
 80 |   
81 |
82 | 83 | !SLIDE 84 | 85 | ## 在 Model 裡寫 view code 86 | 87 | ### 錯誤 88 | 89 | app/models/post.rb 90 | 91 |
92 |
 93 |      def tag_list_for_welcome_page
 94 |         tags.maps {|tag| "<span> tag.name </span>" }.join(" / ")
 95 |      end
 96 |   
97 |
98 | 99 | ### 正確 100 | 101 | app/helpers/post_helper.rb 102 |
103 |
104 |     def tag_list(tags)
105 |       tags.map { |tag| content_tag(:span, tag.name ) }.join(" / ")
106 |     end   
107 |   
108 |
109 | 110 | !SLIDE 111 | 112 | ### 道德底線: Maintainability (維護性,容易找到問題) -------------------------------------------------------------------------------- /.sass-cache/cc68b714c1a90de69617ba28e081c40ad837bc40/ie.scssc: -------------------------------------------------------------------------------- 1 | 3.0.24 (Classy Cassidy) 2 | 55d03cbe8dc4482082815585822d80503557fdcb 3 | o:Sass::Tree::RootNode 4 | : 5 | @linei: @options{: 6 | style: expanded:load_paths[ "./public/stylesheets/sass"C/Users/xdite/Dropbox/presentation/2011-ruby-conf-tw-xdite/sass"o/Applications/compass.app/Contents/Resources/ruby/gem/gems/compass-0.10.6/frameworks/blueprint/stylesheets"~/Applications/compass.app/Contents/Resources/ruby/gem/gems/compass-0.10.6/frameworks/_blueprint_deprecated_imports/stylesheets"m/Applications/compass.app/Contents/Resources/ruby/gem/gems/compass-0.10.6/frameworks/compass/stylesheets"|/Applications/compass.app/Contents/Resources/ruby/gem/gems/compass-0.10.6/frameworks/_compass_deprecated_imports/stylesheets"l/Applications/compass.app/Contents/Resources/ruby/gem/gems/compass-960-plugin-0.10.0/lib/../stylesheets"j/Applications/compass.app/Contents/Resources/ruby/gem/gems/html5-boilerplate-0.2.6/lib/../stylesheets: 7 | cacheT:cache_location"J/Users/xdite/Dropbox/presentation/2011-ruby-conf-tw-xdite/.sass-cache: syntax: scss:full_exceptionT:css_location"./public/stylesheets:always_updateF:always_checkT:line_commentsT:template_location[ [@@[@ "J/Users/xdite/Dropbox/presentation/2011-ruby-conf-tw-xdite/stylesheets[@ 8 | "J/Users/xdite/Dropbox/presentation/2011-ruby-conf-tw-xdite/stylesheets[@ "J/Users/xdite/Dropbox/presentation/2011-ruby-conf-tw-xdite/stylesheets[@ "J/Users/xdite/Dropbox/presentation/2011-ruby-conf-tw-xdite/stylesheets[@ "J/Users/xdite/Dropbox/presentation/2011-ruby-conf-tw-xdite/stylesheets[@"J/Users/xdite/Dropbox/presentation/2011-ruby-conf-tw-xdite/stylesheets[@"J/Users/xdite/Dropbox/presentation/2011-ruby-conf-tw-xdite/stylesheets: filename"K/Users/xdite/Dropbox/presentation/2011-ruby-conf-tw-xdite/sass/ie.scss:property_syntax0:@has_childrenT:@template"/* Welcome to Compass. Use this file to write IE specific override styles. 9 | * Import this file using the following HTML or equivalent: 10 | * */ 13 | :@children[o:Sass::Tree::CommentNode ;i;@: @silent0: @lines[;[: @value"/* Welcome to Compass. Use this file to write IE specific override styles. 14 | * Import this file using the following HTML or equivalent: 15 | * */ -------------------------------------------------------------------------------- /.sass-cache/cc68b714c1a90de69617ba28e081c40ad837bc40/screen.scssc: -------------------------------------------------------------------------------- 1 | 3.0.24 (Classy Cassidy) 2 | e24c39d4800ce9f9b6b50e6a9d2d8c3fce9d548f 3 | o:Sass::Tree::RootNode 4 | : 5 | @linei: @options{: 6 | style: expanded:load_paths[ "./public/stylesheets/sass"C/Users/xdite/Dropbox/presentation/2011-ruby-conf-tw-xdite/sass"o/Applications/compass.app/Contents/Resources/ruby/gem/gems/compass-0.10.6/frameworks/blueprint/stylesheets"~/Applications/compass.app/Contents/Resources/ruby/gem/gems/compass-0.10.6/frameworks/_blueprint_deprecated_imports/stylesheets"m/Applications/compass.app/Contents/Resources/ruby/gem/gems/compass-0.10.6/frameworks/compass/stylesheets"|/Applications/compass.app/Contents/Resources/ruby/gem/gems/compass-0.10.6/frameworks/_compass_deprecated_imports/stylesheets"l/Applications/compass.app/Contents/Resources/ruby/gem/gems/compass-960-plugin-0.10.0/lib/../stylesheets"j/Applications/compass.app/Contents/Resources/ruby/gem/gems/html5-boilerplate-0.2.6/lib/../stylesheets: 7 | cacheT:cache_location"J/Users/xdite/Dropbox/presentation/2011-ruby-conf-tw-xdite/.sass-cache: syntax: scss:full_exceptionT:css_location"./public/stylesheets:always_updateF:always_checkT:line_commentsT:template_location[ [@@[@ "J/Users/xdite/Dropbox/presentation/2011-ruby-conf-tw-xdite/stylesheets[@ 8 | "J/Users/xdite/Dropbox/presentation/2011-ruby-conf-tw-xdite/stylesheets[@ "J/Users/xdite/Dropbox/presentation/2011-ruby-conf-tw-xdite/stylesheets[@ "J/Users/xdite/Dropbox/presentation/2011-ruby-conf-tw-xdite/stylesheets[@ "J/Users/xdite/Dropbox/presentation/2011-ruby-conf-tw-xdite/stylesheets[@"J/Users/xdite/Dropbox/presentation/2011-ruby-conf-tw-xdite/stylesheets[@"J/Users/xdite/Dropbox/presentation/2011-ruby-conf-tw-xdite/stylesheets: filename"O/Users/xdite/Dropbox/presentation/2011-ruby-conf-tw-xdite/sass/screen.scss:property_syntax0:@has_childrenT:@template"'/* Welcome to Compass. 9 | * In this file you should write your main styles. (or centralize your imports) 10 | * Import this file using the following HTML or equivalent: 11 | * */ 12 | 13 | @import "compass/reset"; 14 | :@children[o:Sass::Tree::CommentNode ;i;@: @silent0: @lines[;[: @value" /* Welcome to Compass. 15 | * In this file you should write your main styles. (or centralize your imports) 16 | * Import this file using the following HTML or equivalent: 17 | * */o:Sass::Tree::ImportNode 18 | ;i ;@;0:@imported_filename"compass/reset;[ -------------------------------------------------------------------------------- /stylesheets/screen.css: -------------------------------------------------------------------------------- 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 | /* line 17, ../../../../../../Applications/compass.app/Contents/Resources/ruby/compass_0.11/compass-0.11.5/frameworks/compass/stylesheets/compass/reset/_utilities.scss */ 6 | html, body, div, span, applet, object, iframe, 7 | h1, h2, h3, h4, h5, h6, p, blockquote, pre, 8 | a, abbr, acronym, address, big, cite, code, 9 | del, dfn, em, img, ins, kbd, q, s, samp, 10 | small, strike, strong, sub, sup, tt, var, 11 | b, u, i, center, 12 | dl, dt, dd, ol, ul, li, 13 | fieldset, form, label, legend, 14 | table, caption, tbody, tfoot, thead, tr, th, td, 15 | article, aside, canvas, details, embed, 16 | figure, figcaption, footer, header, hgroup, 17 | menu, nav, output, ruby, section, summary, 18 | time, mark, audio, video { 19 | margin: 0; 20 | padding: 0; 21 | border: 0; 22 | font-size: 100%; 23 | font: inherit; 24 | vertical-align: baseline; 25 | } 26 | 27 | /* line 20, ../../../../../../Applications/compass.app/Contents/Resources/ruby/compass_0.11/compass-0.11.5/frameworks/compass/stylesheets/compass/reset/_utilities.scss */ 28 | body { 29 | line-height: 1; 30 | } 31 | 32 | /* line 22, ../../../../../../Applications/compass.app/Contents/Resources/ruby/compass_0.11/compass-0.11.5/frameworks/compass/stylesheets/compass/reset/_utilities.scss */ 33 | ol, ul { 34 | list-style: none; 35 | } 36 | 37 | /* line 24, ../../../../../../Applications/compass.app/Contents/Resources/ruby/compass_0.11/compass-0.11.5/frameworks/compass/stylesheets/compass/reset/_utilities.scss */ 38 | table { 39 | border-collapse: collapse; 40 | border-spacing: 0; 41 | } 42 | 43 | /* line 26, ../../../../../../Applications/compass.app/Contents/Resources/ruby/compass_0.11/compass-0.11.5/frameworks/compass/stylesheets/compass/reset/_utilities.scss */ 44 | caption, th, td { 45 | text-align: left; 46 | font-weight: normal; 47 | vertical-align: middle; 48 | } 49 | 50 | /* line 28, ../../../../../../Applications/compass.app/Contents/Resources/ruby/compass_0.11/compass-0.11.5/frameworks/compass/stylesheets/compass/reset/_utilities.scss */ 51 | q, blockquote { 52 | quotes: none; 53 | } 54 | /* line 101, ../../../../../../Applications/compass.app/Contents/Resources/ruby/compass_0.11/compass-0.11.5/frameworks/compass/stylesheets/compass/reset/_utilities.scss */ 55 | q:before, q:after, blockquote:before, blockquote:after { 56 | content: ""; 57 | content: none; 58 | } 59 | 60 | /* line 30, ../../../../../../Applications/compass.app/Contents/Resources/ruby/compass_0.11/compass-0.11.5/frameworks/compass/stylesheets/compass/reset/_utilities.scss */ 61 | a img { 62 | border: none; 63 | } 64 | 65 | /* line 114, ../../../../../../Applications/compass.app/Contents/Resources/ruby/compass_0.11/compass-0.11.5/frameworks/compass/stylesheets/compass/reset/_utilities.scss */ 66 | article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section, summary { 67 | display: block; 68 | } 69 | -------------------------------------------------------------------------------- /our_way_to_organize/01_model.md: -------------------------------------------------------------------------------- 1 | !SLIDE 2 | 3 | # Model 4 | 5 | !SLIDE code 6 | 7 | ### Model 8 | 9 |
10 |
 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 |
38 | 39 | !SLIDE code 40 | 41 | ## 續 42 |
43 |
 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 |
 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 |
99 | 100 | !SLIDE 101 | 102 | ## Annotate 103 | 104 |
105 |
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 |
-------------------------------------------------------------------------------- /abusing_rails/abusing_rails.md: -------------------------------------------------------------------------------- 1 | !SLIDE 2 | 3 | # 濫用 Rails 內建機制 4 | ## 隱藏的炸彈 5 | 6 | !SLIDE code bullets left 7 | 8 | ## ABUSE: 濫用 helper 的 magic 9 | 10 |
11 |
 12 |      <%= form_for @model %>
 13 |      <%= form_for [@post,@comment] %>
 14 |      <%= link_to "mode_name", @model %>
 15 |   
16 |
17 | 18 | ### 實作 STI 時,magic 針對 model type 展開,爆光光... 19 | ### 翻修時無法使用 git grep "xxxx_path" 快速找到可能有問題處 20 | 21 | !SLIDE code 22 | 23 | # ABUSE: ORM 無限串接 24 | 25 |


26 | 27 |
28 |
 29 |       post.aa.bb.cc.dd.ee.ff.gg.hh.ii.jj.kk.ll.mm.nn.oo.pp
 30 |   
31 |
32 | 33 |


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 |
 52 |     # match ':controller(/:action(/:id(.:format)))'
 53 |   
54 |
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 |
74 |
 75 |      class ApplicationController < ActionController::Base
 76 |        protect_from_forgery
 77 |      end
 78 |   
79 |
80 | 81 | app/views/layout/application.html.erb 82 |
83 |
 84 |     <%= csrf_meta_tag %>
 85 |   
86 |
87 | 88 | !SLIDE 89 | 90 |
91 |
 92 |     # match ':controller(/:action(/:id(.:format)))'
 93 |   
94 |
95 | 96 | ## 硬幹就失去天然屏障了,任何 action 都可以 get 97 | 98 | !SLIDE center 99 | 100 | 101 |
102 |
103 |     <img src="/posts/delete_all">
104 |   
105 |
106 | 107 | !SLIDE 108 |
109 |

!! VERY DANGER !!

110 |
111 | 112 | !SLIDE 113 | ## Solution 114 | # RESTful ...... please!! 115 | 116 | !SLIDE code 117 | 118 | ## ABUSE: SQL Query in LOOP 119 |
120 |
121 |     <% Post.limit(10).each do |post| %>
122 |     <%= post.categories.map{ |c| "<span>#{c.name}</span>"} =%> 
123 |     <% end %>
124 |   
125 |
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 |
142 |
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 |
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 |
10 |
 11 |     class Post < ActiveRecord::Base
 12 |       include Techbang::PostBase
 13 |       
 14 |       # ... some bussiness logic method here
 15 |     end
 16 |   
17 |
18 | 19 | !SLIDE code 20 | 21 | ### Common Behavior 22 | 23 |
24 |
 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 |
53 | 54 | !SLIDE left 55 | 56 | ## 使用 STI / NameSpace 57 | 58 | ### Single Table Inheritance 59 | 60 |
61 |
 62 |      class TechbangPost < Post
 63 |      end
 64 |     
 65 |      class AdvertisePost < Post
 66 |      end
 67 |   
68 |
69 | 70 | ### NameSpace 71 | 72 |
73 |
 74 |      class User::Profile < ActiveRecord::Base
 75 |      end
 76 |     
 77 |      class User::Preference < ActiveRecord::Base
 78 |      end
 79 |   
80 |
81 | 82 | !SLIDE code 83 | 84 | ## Extract to composed class 85 | 86 |
87 |
 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 |
106 | 107 | !SLIDE 108 | 109 | ## 類似作用與名稱的 Model 超過 2 個請注意 110 | 111 | !SLIDE code 112 | 113 | ## Polymorphic Association 114 | 115 | ### Bad Smell 116 | 117 |
118 |
119 |     class PostComment < ActiveRecord::Base
120 |     class PhotoCommenct < ActiveRecord::Base
121 |   
122 |
123 | ### Good Smell 124 |
125 |
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 |
139 | 140 | !SLIDE 141 | 142 | ## column 超過 10 個請注意 143 | 144 | !SLIDE 145 | 146 | ## Virtual Attribute 147 | 148 |
149 |
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 |
164 | 165 | ### (用 getter / setter 造出 virtual attribute) 166 | 167 | !SLIDE 168 | 169 | ## Serialize 170 | 171 |
172 |
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 |
183 | 184 | ### (把小資料存在同一個 column 內) -------------------------------------------------------------------------------- /organize/2_controller.md: -------------------------------------------------------------------------------- 1 | !SLIDE 2 | 3 | ### 類似的 code 在同一個 controller 出現第3次請注意 4 | 5 | !SLIDE code 6 | 7 | ## 使用 before_filter 整理 8 | 9 |
10 |
 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 |
30 | 31 | !SLIDE 32 | 33 | ### 相同的 method 在不同 controller 出現第二次出現請注意 34 | 35 | !SLIDE 36 | 37 | ## 搬到 application controller 38 | 39 |
40 |
 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 |
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 |
69 |
 70 |       class UserFavoritesController < ApplicationController
 71 |     
 72 |       class UserProfileController < ApplicationController
 73 |       
 74 |   
75 |
76 | 77 | ### GOOD SMELL 78 | app/controller/user/favorites_controller.rb 79 |
80 |
 81 |       class User::FavoritesController < ApplicationController
 82 |       
 83 |       class User::ProfileController < ApplicationController
 84 |       
 85 |   
86 |
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 |
123 |
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 |
137 | 138 | !SLIDE smallest 139 | 140 | # Use presenter in controller 141 |
142 |
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 |
154 | 155 | !SLIDE 156 | 157 | ## 儲存之前、儲存之後需要 do something 158 | 159 | !SLIDE code 160 | 161 | ## BAD SMELL 162 | 163 |
164 |
165 |       if @post.save
166 |         @post.delay.update_search_index
167 |       end
168 |   
169 |
170 | 171 | !SLIDE code 172 | 173 | ## 善用 model callbacks 174 |
175 |
176 |     class Post < ActiveRecord::Base
177 |       after_save :update_search_index
178 |     end
179 |   
180 |
181 | 182 | ## 或者是 Observer 183 | 184 |
185 |
186 |     class PostObserver < ActiveRecord::Observer
187 |       observ :post
188 |       
189 |       def after_save(post)
190 |         update_search_index
191 |       end
192 |     end
193 |   
194 |
-------------------------------------------------------------------------------- /bad_code/bad_code.md: -------------------------------------------------------------------------------- 1 | !SLIDE bullets incremental left 2 | 3 | ## 為什麼 Code 這麼容易腐敗? 4 | 5 | !SLIDE 6 | 7 | ## 其實大多數 Rails Developer 不會寫 Rails 8 | 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 | 26 |
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 |
59 |
 60 |   def t_tags
 61 |     t_list.join(" ")
 62 |   end
 63 | 
64 |
65 | 66 | ### 容易理解 67 | 68 |
69 |
 70 |   def tokenized_tags
 71 |     tag_list.join(" ")
 72 |   end
 73 | 
74 |
75 | 76 | !SLIDE 77 | 78 | # 能夠不縮寫就不縮寫 79 | ### 真的太長的 method name ( 3個詞以上),使用 module 或 namespace 80 | 81 | !SLIDE code left 82 | 83 | # 無法了解意義的變數 84 | 85 | ## 錯誤 86 | 87 |
88 |
 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 |
102 | 103 | !SLIDE code left 104 | 105 | ## 正確 106 | 107 |
108 |
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 |
121 | 122 | !SLIDE 123 | 124 | # 濫用 elsif 125 | ## 不好的寫作習慣 126 | 127 | !SLIDE code 128 | 129 | ## 邏輯混亂 130 | 131 |
132 |
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 |
144 | 145 | !SLIDE code 146 | 147 | ## 容易理解 148 | 149 |
150 |
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 |
167 | 168 | !SLIDE 169 | 170 | # 語意不明 171 | ## 不好的寫作習慣 172 | 173 | !SLIDE code 174 | 175 | ## 動詞 / 名詞 / 形容詞 傻傻搞不清楚 176 | 177 | ### 錯誤 178 | 179 |
180 |
181 |   post.is_hide
182 |   
183 |
184 | 185 | ### 正確 186 | 187 |
188 |
189 |   post.is_hidden
190 |   
191 |
192 | 193 | !SLIDE code 194 | 195 | ## 是不是 spam ? => 疑問,回傳 true / false 196 | 197 |
198 |
199 |     post.is_spam?
200 |   
201 |
202 | 203 | ## 標記為 spam! => bang,改變狀態 204 | 205 |
206 |
207 |     post.is_spam!
208 |   
209 |
210 | 211 | !SLIDE 212 | 213 | # 濫用自創名詞 214 | ## 不好的寫作習慣 215 | 216 | !SLIDE code 217 | 218 | ## 攻 / 受 ( 錯誤示範 ) 219 | 220 |
221 |
222 |   attacker / defender 
223 |   
224 |
225 | 226 | ## 傳送者 / 接收者 ( 正確示範 ) 227 | 228 |
229 |
230 |   sender / reciever
231 |   
232 |
233 | 234 | !SLIDE 235 | 236 | ## 類似的 method,變數與寫法不一致 237 | ### 不好的寫作習慣 238 | 239 | !SLIDE center 240 | 241 | ### 一下使用 block, 一下使用 lambda 242 | 243 | 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 | --------------------------------------------------------------------------------