SlideShare une entreprise Scribd logo
1  sur  51
Our Presentation Will Begin Shortly

Rails AntiPatterns
Workshop
May 12, 2011


          Matt Reider, Director of Training
          Engine Yard


          Chad Pytel, Founder & CEO
          thoughtbot Inc.
Rake Tasks
Are you testing them?
What makes them hard to test?

   • Scripts that live outside app
   • Often have network and file access
   • Often have output
Example Task

namespace :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
One possible way to test
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
should "print a message at the beginning" do
  assert_match /Searching/i, @out
end
should "find all tweets containing @cpytel" do
  # this one would be based entirely on luck.
end
This Has Problems

• Slow
• No mocking or stubbing available
• Task isn’t in a transaction
Basically, no sandboxing
How do we fix this?
Rake tasks are just Ruby
Move it all into the Model
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.
  end
end
The Task is Nice and Skinny

namespace :twitter do
  task :search => :environment do
    Alert.create_all_from_twitter_search
  end
end
Testing is Pretty Normal

# test/unit/alert_test.rb
class 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
should "print a message at the beginning" do
  Alert.create_all_from_twitter_search(@output)
  assert_match /Searching/i, @output.string
end
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
should "find all tweets containing @cpytel" do
  Twitter.expects(:search).
          with("@cpytel").
          returns(["body"])
  Alert.create_all_from_twitter_search(@output)
end
We can mock and stub!
We can use normal tools!


• FakeWeb/WebMock
• FileUtils::NoWrite
In Summary

• You can test drive development of
  your rake tasks
• Rake tasks should live inside a
  model (or class)
Views
Know Your Helpers
Know How They Change
# Edit form
<%= form_for :user,
             :url => user_path(@user),
             :html => {:method => :put} do |form| %>
<%= form_for @user do |form| %>
<!-- 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 -%>
Move the post content
    into a partial
<!-- 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>
Looping was built
  into render
<!-- 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>
<!-- 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>
<%= render :partial => @posts %>
<%= render @posts %>
Dynamic Page Titles
<!-- layouts/application.html.erb -->
<head>
  <title>
    Acme Widgets : TX-300 Utility Widget
  </title>
</head>
class PagesController < ApplicationController
  def show
    @widget = Widgets.find(params[:id])
    @title = @widget.name
  end
end

<!-- layouts/application.html.erb -->
<head>
  <title>Acme Widgets : <%= @title %></title>
</head>
This is all View
There is a Helper
<!-- layouts/application.html.erb -->
<head>
  <title>
    Acme Widgets : <%= yield(:title) %>
  </title>
</head>

<!-- widgets/show.html.erb -->
<% content_for :title, @widget.title %>
Default Title
<!-- layouts/application.html.erb -->
<head>
  <title>
    Acme Widgets : <%= yield(:title) || "Home" %>
  </title>
</head>
What else can we use
      this for?
<!-- 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>
<!-- 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 %>
Avoid Duplication
<!-- 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 %>
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>

<!-- app/views/products/show.html.erb -->
<% content_for :sidebar do %>
  This is content for the sidebar.
  <%= link_to "Your Account", account_url %>
<% end %>
Upcoming Classes


Zero to Rails 3 in four days
•May 23-26
•Virtual

Rails AntiPatterns
•Best Practices
•Boston – June 6 & 7
•San Francisco – June 13 & 14




   Learn more at: Engineyard.com/university

Contenu connexe

Tendances

jQuery Plugin Creation
jQuery Plugin CreationjQuery Plugin Creation
jQuery Plugin Creation
benalman
 
Action View Form Helpers - 1, Season 2
Action View Form Helpers - 1, Season 2Action View Form Helpers - 1, Season 2
Action View Form Helpers - 1, Season 2
RORLAB
 
PowerShell with SharePoint 2013 and Office 365 - EPC Group
PowerShell with SharePoint 2013 and Office 365 - EPC GroupPowerShell with SharePoint 2013 and Office 365 - EPC Group
PowerShell with SharePoint 2013 and Office 365 - EPC Group
EPC Group
 

Tendances (20)

Introduction à Ruby
Introduction à RubyIntroduction à Ruby
Introduction à Ruby
 
SproutCore is Awesome - HTML5 Summer DevFest
SproutCore is Awesome - HTML5 Summer DevFestSproutCore is Awesome - HTML5 Summer DevFest
SproutCore is Awesome - HTML5 Summer DevFest
 
Introduccion app engine con python
Introduccion app engine con pythonIntroduccion app engine con python
Introduccion app engine con python
 
jQuery Plugin Creation
jQuery Plugin CreationjQuery Plugin Creation
jQuery Plugin Creation
 
Plugin jQuery, Design Patterns
Plugin jQuery, Design PatternsPlugin jQuery, Design Patterns
Plugin jQuery, Design Patterns
 
Best Practices in Plugin Development (WordCamp Seattle)
Best Practices in Plugin Development (WordCamp Seattle)Best Practices in Plugin Development (WordCamp Seattle)
Best Practices in Plugin Development (WordCamp Seattle)
 
Hooked on WordPress: WordCamp Columbus
Hooked on WordPress: WordCamp ColumbusHooked on WordPress: WordCamp Columbus
Hooked on WordPress: WordCamp Columbus
 
Action View Form Helpers - 1, Season 2
Action View Form Helpers - 1, Season 2Action View Form Helpers - 1, Season 2
Action View Form Helpers - 1, Season 2
 
Denver emberjs-sept-2015
Denver emberjs-sept-2015Denver emberjs-sept-2015
Denver emberjs-sept-2015
 
Writing Software not Code with Cucumber
Writing Software not Code with CucumberWriting Software not Code with Cucumber
Writing Software not Code with Cucumber
 
Powershell to the People #suguk
Powershell to the People #sugukPowershell to the People #suguk
Powershell to the People #suguk
 
16.mysql stored procedures in laravel
16.mysql stored procedures in laravel16.mysql stored procedures in laravel
16.mysql stored procedures in laravel
 
Creating Themes
Creating ThemesCreating Themes
Creating Themes
 
Django
DjangoDjango
Django
 
Build a bot workshop async primer - php[tek]
Build a bot workshop  async primer - php[tek]Build a bot workshop  async primer - php[tek]
Build a bot workshop async primer - php[tek]
 
Web development with django - Basics Presentation
Web development with django - Basics PresentationWeb development with django - Basics Presentation
Web development with django - Basics Presentation
 
PowerShell with SharePoint 2013 and Office 365 - EPC Group
PowerShell with SharePoint 2013 and Office 365 - EPC GroupPowerShell with SharePoint 2013 and Office 365 - EPC Group
PowerShell with SharePoint 2013 and Office 365 - EPC Group
 
How To Write a WordPress Plugin
How To Write a WordPress PluginHow To Write a WordPress Plugin
How To Write a WordPress Plugin
 
Rails for Beginners - Le Wagon
Rails for Beginners - Le WagonRails for Beginners - Le Wagon
Rails for Beginners - Le Wagon
 
The effective use of Django ORM
The effective use of Django ORMThe effective use of Django ORM
The effective use of Django ORM
 

Similaire à Rails Antipatterns | Open Session with Chad Pytel

Desenvolvimento web com Ruby on Rails (parte 2)
Desenvolvimento web com Ruby on Rails (parte 2)Desenvolvimento web com Ruby on Rails (parte 2)
Desenvolvimento web com Ruby on Rails (parte 2)
Joao Lucas Santana
 
OSDC 2009 Rails Turtorial
OSDC 2009 Rails TurtorialOSDC 2009 Rails Turtorial
OSDC 2009 Rails Turtorial
Yi-Ting Cheng
 
Rails 3 overview
Rails 3 overviewRails 3 overview
Rails 3 overview
Yehuda Katz
 
TurboGears2 Pluggable Applications
TurboGears2 Pluggable ApplicationsTurboGears2 Pluggable Applications
TurboGears2 Pluggable Applications
Alessandro Molina
 
Система рендеринга в Magento
Система рендеринга в MagentoСистема рендеринга в Magento
Система рендеринга в Magento
Magecom Ukraine
 
Resource and view
Resource and viewResource and view
Resource and view
Papp Laszlo
 

Similaire à Rails Antipatterns | Open Session with Chad Pytel (20)

You're Doing It Wrong
You're Doing It WrongYou're Doing It Wrong
You're Doing It Wrong
 
Mojolicious
MojoliciousMojolicious
Mojolicious
 
Desenvolvimento web com Ruby on Rails (parte 2)
Desenvolvimento web com Ruby on Rails (parte 2)Desenvolvimento web com Ruby on Rails (parte 2)
Desenvolvimento web com Ruby on Rails (parte 2)
 
OSDC 2009 Rails Turtorial
OSDC 2009 Rails TurtorialOSDC 2009 Rails Turtorial
OSDC 2009 Rails Turtorial
 
Turbogears Presentation
Turbogears PresentationTurbogears Presentation
Turbogears Presentation
 
Rails 3 overview
Rails 3 overviewRails 3 overview
Rails 3 overview
 
Django crush course
Django crush course Django crush course
Django crush course
 
TurboGears2 Pluggable Applications
TurboGears2 Pluggable ApplicationsTurboGears2 Pluggable Applications
TurboGears2 Pluggable Applications
 
Ruby on Rails - Introduction
Ruby on Rails - IntroductionRuby on Rails - Introduction
Ruby on Rails - Introduction
 
What's new in Rails 2?
What's new in Rails 2?What's new in Rails 2?
What's new in Rails 2?
 
Implement rich snippets in your webshop
Implement rich snippets in your webshopImplement rich snippets in your webshop
Implement rich snippets in your webshop
 
Building Cloud Castles
Building Cloud CastlesBuilding Cloud Castles
Building Cloud Castles
 
Система рендеринга в Magento
Система рендеринга в MagentoСистема рендеринга в Magento
Система рендеринга в Magento
 
Practical catalyst
Practical catalystPractical catalyst
Practical catalyst
 
Geek Moot '09 -- Smarty 101
Geek Moot '09 -- Smarty 101Geek Moot '09 -- Smarty 101
Geek Moot '09 -- Smarty 101
 
The Django Web Application Framework 2
The Django Web Application Framework 2The Django Web Application Framework 2
The Django Web Application Framework 2
 
The Django Web Application Framework 2
The Django Web Application Framework 2The Django Web Application Framework 2
The Django Web Application Framework 2
 
DRYing Up Rails Views and Controllers
DRYing Up Rails Views and ControllersDRYing Up Rails Views and Controllers
DRYing Up Rails Views and Controllers
 
Resource and view
Resource and viewResource and view
Resource and view
 
The Django Web Application Framework 2
The Django Web Application Framework 2The Django Web Application Framework 2
The Django Web Application Framework 2
 

Plus de Engine Yard

Engine Yard Partner Program 2014
Engine Yard Partner Program 2014Engine Yard Partner Program 2014
Engine Yard Partner Program 2014
Engine Yard
 
Rubinius and Ruby | A Love Story
Rubinius and Ruby | A Love Story Rubinius and Ruby | A Love Story
Rubinius and Ruby | A Love Story
Engine Yard
 
Everything Rubinius
Everything RubiniusEverything Rubinius
Everything Rubinius
Engine Yard
 

Plus de Engine Yard (19)

Engine Yard Partner Program 2014
Engine Yard Partner Program 2014Engine Yard Partner Program 2014
Engine Yard Partner Program 2014
 
Getting Started with PHP on Engine Yard Cloud
Getting Started with PHP on Engine Yard CloudGetting Started with PHP on Engine Yard Cloud
Getting Started with PHP on Engine Yard Cloud
 
Engine Yard Cloud Architecture Enhancements
Engine Yard Cloud Architecture EnhancementsEngine Yard Cloud Architecture Enhancements
Engine Yard Cloud Architecture Enhancements
 
6 tips for improving ruby performance
6 tips for improving ruby performance6 tips for improving ruby performance
6 tips for improving ruby performance
 
Simplifying PCI on a PaaS Environment
Simplifying PCI on a PaaS EnvironmentSimplifying PCI on a PaaS Environment
Simplifying PCI on a PaaS Environment
 
The Tao of Documentation
The Tao of DocumentationThe Tao of Documentation
The Tao of Documentation
 
Innovate Faster in the Cloud with a Platform as a Service
Innovate Faster in the Cloud with a Platform as a ServiceInnovate Faster in the Cloud with a Platform as a Service
Innovate Faster in the Cloud with a Platform as a Service
 
Introduction to Ruby
Introduction to RubyIntroduction to Ruby
Introduction to Ruby
 
JRuby: Enhancing Java Developers Lives
JRuby: Enhancing Java Developers LivesJRuby: Enhancing Java Developers Lives
JRuby: Enhancing Java Developers Lives
 
High Performance Ruby: Evented vs. Threaded
High Performance Ruby: Evented vs. ThreadedHigh Performance Ruby: Evented vs. Threaded
High Performance Ruby: Evented vs. Threaded
 
Release Early & Release Often: Reducing Deployment Friction
Release Early & Release Often: Reducing Deployment FrictionRelease Early & Release Often: Reducing Deployment Friction
Release Early & Release Often: Reducing Deployment Friction
 
JRuby Jam Session
JRuby Jam Session JRuby Jam Session
JRuby Jam Session
 
Rubinius and Ruby | A Love Story
Rubinius and Ruby | A Love Story Rubinius and Ruby | A Love Story
Rubinius and Ruby | A Love Story
 
JRuby: Apples and Oranges
JRuby: Apples and OrangesJRuby: Apples and Oranges
JRuby: Apples and Oranges
 
Developing a Language
Developing a LanguageDeveloping a Language
Developing a Language
 
Debugging Ruby Systems
Debugging Ruby SystemsDebugging Ruby Systems
Debugging Ruby Systems
 
Geemus
GeemusGeemus
Geemus
 
Everything Rubinius
Everything RubiniusEverything Rubinius
Everything Rubinius
 
Rails Hosting and the Woes
Rails Hosting and the WoesRails Hosting and the Woes
Rails Hosting and the Woes
 

Dernier

Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Safe Software
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
?#DUbAI#??##{{(☎️+971_581248768%)**%*]'#abortion pills for sale in dubai@
 

Dernier (20)

Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
 
ICT role in 21st century education and its challenges
ICT role in 21st century education and its challengesICT role in 21st century education and its challenges
ICT role in 21st century education and its challenges
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
 
DBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor PresentationDBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor Presentation
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingRepurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century education
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdf
 
A Beginners Guide to Building a RAG App Using Open Source Milvus
A Beginners Guide to Building a RAG App Using Open Source MilvusA Beginners Guide to Building a RAG App Using Open Source Milvus
A Beginners Guide to Building a RAG App Using Open Source Milvus
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
 
Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CV
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
 

Rails Antipatterns | Open Session with Chad Pytel

  • 1. Our Presentation Will Begin Shortly Rails AntiPatterns Workshop May 12, 2011 Matt Reider, Director of Training Engine Yard Chad Pytel, Founder & CEO thoughtbot Inc.
  • 4. What makes them hard to test? • Scripts that live outside app • Often have network and file access • Often have output
  • 5. Example Task namespace :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. 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
  • 8. should "print a message at the beginning" do assert_match /Searching/i, @out end
  • 9. should "find all tweets containing @cpytel" do # this one would be based entirely on luck. end
  • 10. This Has Problems • Slow • No mocking or stubbing available • Task isn’t in a transaction
  • 12. How do we fix this?
  • 13. Rake tasks are just Ruby
  • 14. Move it all into the Model
  • 15. 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. end end
  • 16. The Task is Nice and Skinny namespace :twitter do task :search => :environment do Alert.create_all_from_twitter_search end end
  • 17. Testing is Pretty Normal # test/unit/alert_test.rb class 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
  • 18. should "print a message at the beginning" do Alert.create_all_from_twitter_search(@output) assert_match /Searching/i, @output.string end
  • 19. 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
  • 20. should "find all tweets containing @cpytel" do Twitter.expects(:search). with("@cpytel"). returns(["body"]) Alert.create_all_from_twitter_search(@output) end
  • 21. We can mock and stub!
  • 22. We can use normal tools! • FakeWeb/WebMock • FileUtils::NoWrite
  • 23. In Summary • You can test drive development of your rake tasks • Rake tasks should live inside a model (or class)
  • 24. Views
  • 26. Know How They Change
  • 27. # Edit form <%= form_for :user, :url => user_path(@user), :html => {:method => :put} do |form| %>
  • 28. <%= form_for @user do |form| %>
  • 29. <!-- 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 -%>
  • 30. Move the post content into a partial
  • 31. <!-- 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>
  • 32. Looping was built into render
  • 33. <!-- 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>
  • 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. <%= render :partial => @posts %>
  • 38. <!-- layouts/application.html.erb --> <head> <title> Acme Widgets : TX-300 Utility Widget </title> </head>
  • 39. class PagesController < ApplicationController def show @widget = Widgets.find(params[:id]) @title = @widget.name end end <!-- layouts/application.html.erb --> <head> <title>Acme Widgets : <%= @title %></title> </head>
  • 40. This is all View
  • 41. There is a Helper
  • 42. <!-- layouts/application.html.erb --> <head> <title> Acme Widgets : <%= yield(:title) %> </title> </head> <!-- widgets/show.html.erb --> <% content_for :title, @widget.title %>
  • 44. <!-- layouts/application.html.erb --> <head> <title> Acme Widgets : <%= yield(:title) || "Home" %> </title> </head>
  • 45. What else can we use this for?
  • 46. <!-- 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>
  • 47. <!-- 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. <!-- 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 %>
  • 50. 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> <!-- app/views/products/show.html.erb --> <% content_for :sidebar do %> This is content for the sidebar. <%= link_to "Your Account", account_url %> <% end %>
  • 51. Upcoming Classes Zero to Rails 3 in four days •May 23-26 •Virtual Rails AntiPatterns •Best Practices •Boston – June 6 & 7 •San Francisco – June 13 & 14 Learn more at: Engineyard.com/university

Notes de l'éditeur

  1. \n
  2. \n
  3. \n
  4. \n
  5. \n
  6. \n
  7. \n
  8. \n
  9. \n
  10. \n
  11. \n
  12. \n
  13. \n
  14. \n
  15. \n
  16. \n
  17. \n
  18. \n
  19. \n
  20. \n
  21. \n
  22. \n
  23. \n
  24. \n
  25. \n
  26. \n
  27. \n
  28. \n
  29. \n
  30. \n
  31. \n
  32. \n
  33. \n
  34. \n
  35. \n
  36. \n
  37. \n
  38. \n
  39. \n
  40. \n
  41. \n
  42. \n
  43. \n
  44. \n
  45. \n
  46. \n
  47. \n
  48. \n
  49. \n
  50. \n
  51. \n