Your SlideShare is downloading. ×
  • Like
You're Doing It Wrong
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×

Now you can save presentations on your phone or tablet

Available for both IPhone and Android

Text the download link to your phone

Standard text messaging rates apply

You're Doing It Wrong

  • 1,073 views
Published

Chad Pytel from Thoughtbot's December 14, 2010 presentation on Rails Antipatters given at BostonRB

Chad Pytel from Thoughtbot's December 14, 2010 presentation on Rails Antipatters given at BostonRB

Published in Technology
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
No Downloads

Views

Total Views
1,073
On SlideShare
0
From Embeds
0
Number of Embeds
0

Actions

Shares
Downloads
9
Comments
0
Likes
1

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n

Transcript

  • 1. You’re Doing It Wrong Chad Pytel cpytel@thoughtbot.com @cpytel
  • 2. You’re Doing It Wrong but I love you anyway Chad Pytel cpytel@thoughtbot.com @cpytel
  • 3. Rake Tasks
  • 4. Are you testing them?
  • 5. What makes them hard to test? • Scripts that live outside app • Often have network and file access • Often have output
  • 6. Example Tasknamespace :twitter do task :search => :environment do puts "Searching twitter." Twitter.search("@cpytel").each do |result| puts "Processing #{result.inspect}." alert = Alert.create(:body => result) alert.save_cache_file! end end puts "All done!"end
  • 7. One possible way to test
  • 8. context "rake twitter:search" do setup do # How slow is this going to be? Very. @out = `cd #{Rails.root} && rake twitter:search 2>&1` end
  • 9. should "print a message at the beginning" do assert_match /Searching/i, @outend
  • 10. should "find all tweets containing @cpytel" do # this one would be based entirely on luck.end
  • 11. This Has Problems• Slow• No mocking or stubbing available• Task isn’t in a transaction
  • 12. Basically, no sandboxing
  • 13. How do we fix this?
  • 14. Rake tasks are just Ruby
  • 15. Move it all into the Model
  • 16. class Alert < ActiveRecord::Base def self.create_all_from_twitter_search(output = $stdout) output.puts "Searching twitter." Twitter.search("@cpytel").each do |result| output.puts "Processing #{result.inspect}." alert = create(:body => result) alert.save_cache_file! end output.puts "All done!" end def save_cache_file! # Removes a file from the filesystem. endend
  • 17. The Task is Nice and Skinnynamespace :twitter do task :search => :environment do Alert.create_all_from_twitter_search endend
  • 18. Testing is Pretty Normal# test/unit/alert_test.rbclass AlertTest < ActiveSupport::TestCase context "create_all_from_twitter_search" do setup do # Make sure none of the tests below hit the # network or touch the filesystem. Alert.any_instance.stubs(:save_cache_file!) Twitter.stubs(:search).returns([]) @output = StringIO.new end
  • 19. should "print a message at the beginning" do Alert.create_all_from_twitter_search(@output) assert_match /Searching/i, @output.stringend
  • 20. should "save some cache files" do Twitter.stubs(:search).returns(["one"]) alert = mock("alert") alert.expects(:save_cache_file!) Alert.stubs(:create).returns(alert) Alert.create_all_from_twitter_search(@output)end
  • 21. should "find all tweets containing @cpytel" do Twitter.expects(:search). with("@cpytel"). returns(["body"]) Alert.create_all_from_twitter_search(@output)end
  • 22. We can mock and stub!
  • 23. We can use normal tools!• FakeWeb/WebMock• FileUtils::NoWrite
  • 24. In Summary• You can test drive development of your rake tasks• Rake tasks should live inside a model (or class)
  • 25. Views
  • 26. Know Your Helpers
  • 27. Know How They Change
  • 28. # Edit form<%= form_for :user, :url => user_path(@user), :html => {:method => :put} do |form| %>
  • 29. <%= form_for @user do |form| %>
  • 30. <!-- posts/index.html.erb --><% @posts.each do |post| -%> <h2><%= post.title %></h2> <%= format_content post.body %> <p> <%= link_to Email author, mail_to(post.user.email) %> </p><% end -%>
  • 31. Move the post content into a partial
  • 32. <!-- posts/index.html.erb --><% @posts.each do |post| -%> <%= render :partial => post, :object => :post %><% end -%><!-- posts/_post.erb --><h2><%= post.title %></h2><%= format_content post.body %><p><%= link_to Email author,mail_to(post.user.email) %></p>
  • 33. Looping was built into render
  • 34. <!-- posts/index.html.erb --><%= render :partial => post, :collection => @posts %><!-- posts/_post.erb --><h2><%= post.title %></h2><%= format_content post.body %><p> <%= link_to Email author, mail_to(post.user.email) %></p>
  • 35. <!-- posts/index.html.erb --><%= render :partial => post, :collection => @posts %><!-- posts/_post.erb --><h2><%= post.title %></h2><%= format_content post.body %><p> <%= link_to Email author, mail_to(post.user.email) %></p>
  • 36. <%= render :partial => @posts %>
  • 37. <%= render @posts %>
  • 38. Dynamic Page Titles
  • 39. <!-- layouts/application.html.erb --><head> <title> Acme Widgets : TX-300 Utility Widget </title></head>
  • 40. class PagesController < ApplicationController def show @widget = Widgets.find(params[:id]) @title = @widget.name endend<!-- layouts/application.html.erb --><head> <title>Acme Widgets : <%= @title %></title></head>
  • 41. This is all View
  • 42. There is a Helper
  • 43. <!-- layouts/application.html.erb --><head> <title> Acme Widgets : <%= yield(:title) %> </title></head><!-- widgets/show.html.erb --><% content_for :title, @widget.title %>
  • 44. Default Title
  • 45. <!-- layouts/application.html.erb --><head> <title> Acme Widgets : <%= yield(:title) || "Home" %> </title></head>
  • 46. What else can we use this for?
  • 47. <!-- layouts/application.html.erb --><div class="sidebar"> This is content for the sidebar. <%= link_to "Your Account", account_url %></div><div class="main"> The main content of the page</div>
  • 48. <!-- layouts/application.html.erb --><%= yield(:sidebar) %><div class="main"> The main content of the page</div><!-- layouts/application.html.erb --><% content_for :sidebar do %> <div class="sidebar"> This is content for the sidebar. <%= link_to "Your Account", account_url %> </div><% end %>
  • 49. Avoid Duplication
  • 50. <!-- layouts/application.html.erb --><div class="sidebar"> <%= yield(:sidebar) %></div><div class="main"> The main content of the page</div><!-- layouts/application.html.erb --><% content_for :sidebar do %> This is content for the sidebar. <%= link_to "Your Account", account_url %><% end %>
  • 51. Conditional Sidebar<!-- layouts/application.html.erb --><% if content_for?(:sidebar) -%> <div class="sidebar"> <%= yield(:sidebar) %> </div><% end -%><div class="main"> The main content of the page</div><!-- layouts/application.html.erb --><% content_for :sidebar do %> This is content for the sidebar. <%= link_to "Your Account", account_url %><% end %>
  • 52. Reviews/Refactoring