SlideShare une entreprise Scribd logo
1  sur  53
You’re Doing It Wrong

           Chad Pytel
     cpytel@thoughtbot.com
            @cpytel
You’re Doing It Wrong
      but I love you anyway




           Chad Pytel
     cpytel@thoughtbot.com
            @cpytel
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>

<!-- layouts/application.html.erb -->
<% content_for :sidebar do %>
  This is content for the sidebar.
  <%= link_to "Your Account", account_url %>
<% end %>
Reviews/Refactoring

Contenu connexe

Tendances

Tendances (19)

Cucumber Ru09 Web
Cucumber Ru09 WebCucumber Ru09 Web
Cucumber Ru09 Web
 
Selenium sandwich-2
Selenium sandwich-2Selenium sandwich-2
Selenium sandwich-2
 
Rails Awesome Email
Rails Awesome EmailRails Awesome Email
Rails Awesome Email
 
SproutCore is Awesome - HTML5 Summer DevFest
SproutCore is Awesome - HTML5 Summer DevFestSproutCore is Awesome - HTML5 Summer DevFest
SproutCore is Awesome - HTML5 Summer DevFest
 
WordPress maintenance - Keeping it all running smoothly
WordPress maintenance - Keeping it all running smoothlyWordPress maintenance - Keeping it all running smoothly
WordPress maintenance - Keeping it all running smoothly
 
Performance
PerformancePerformance
Performance
 
A different thought angular js part-3
A different thought   angular js part-3A different thought   angular js part-3
A different thought angular js part-3
 
Rspec API Documentation
Rspec API DocumentationRspec API Documentation
Rspec API Documentation
 
Merb Router
Merb RouterMerb Router
Merb Router
 
Cucumber testing
Cucumber testingCucumber testing
Cucumber testing
 
NYC Pyladies talk May 2, 2013
NYC Pyladies talk May 2, 2013NYC Pyladies talk May 2, 2013
NYC Pyladies talk May 2, 2013
 
jQuery Performance Rules
jQuery Performance RulesjQuery Performance Rules
jQuery Performance Rules
 
Introduction to JQuery
Introduction to JQueryIntroduction to JQuery
Introduction to JQuery
 
Prezdev parsing & crawling libs
Prezdev parsing & crawling libsPrezdev parsing & crawling libs
Prezdev parsing & crawling libs
 
Angular data binding by Soft Solutions4U
Angular data binding by Soft Solutions4UAngular data binding by Soft Solutions4U
Angular data binding by Soft Solutions4U
 
Haml in 5 minutes
Haml in 5 minutesHaml in 5 minutes
Haml in 5 minutes
 
Get up and running with google app engine in 60 minutes or less
Get up and running with google app engine in 60 minutes or lessGet up and running with google app engine in 60 minutes or less
Get up and running with google app engine in 60 minutes or less
 
Cain & Obenland — Episode 4
Cain & Obenland — Episode 4Cain & Obenland — Episode 4
Cain & Obenland — Episode 4
 
GAEO
GAEOGAEO
GAEO
 

En vedette (6)

Protecting Your Online Persona
Protecting Your Online PersonaProtecting Your Online Persona
Protecting Your Online Persona
 
IT Club GTA - Project Management - Introduction
IT Club GTA - Project Management - IntroductionIT Club GTA - Project Management - Introduction
IT Club GTA - Project Management - Introduction
 
Mongodb in-anger-boston-rb-2011
Mongodb in-anger-boston-rb-2011Mongodb in-anger-boston-rb-2011
Mongodb in-anger-boston-rb-2011
 
Capybara-Webkit
Capybara-WebkitCapybara-Webkit
Capybara-Webkit
 
MacRuby
MacRubyMacRuby
MacRuby
 
Rspec presentation
Rspec presentationRspec presentation
Rspec presentation
 

Similaire à You're Doing It Wrong

Rails 3: Dashing to the Finish
Rails 3: Dashing to the FinishRails 3: Dashing to the Finish
Rails 3: Dashing to the Finish
Yehuda Katz
 
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
 
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
 
Use Symfony2 components inside WordPress
Use Symfony2 components inside WordPress Use Symfony2 components inside WordPress
Use Symfony2 components inside WordPress
Maurizio Pelizzone
 
Система рендеринга в Magento
Система рендеринга в MagentoСистема рендеринга в Magento
Система рендеринга в Magento
Magecom Ukraine
 

Similaire à You're Doing It Wrong (20)

Mojolicious
MojoliciousMojolicious
Mojolicious
 
Django crush course
Django crush course Django crush course
Django crush course
 
Building Cloud Castles
Building Cloud CastlesBuilding Cloud Castles
Building Cloud Castles
 
Rails 3: Dashing to the Finish
Rails 3: Dashing to the FinishRails 3: Dashing to the Finish
Rails 3: Dashing to the Finish
 
Turbogears Presentation
Turbogears PresentationTurbogears Presentation
Turbogears Presentation
 
Rails 3 overview
Rails 3 overviewRails 3 overview
Rails 3 overview
 
TurboGears2 Pluggable Applications
TurboGears2 Pluggable ApplicationsTurboGears2 Pluggable Applications
TurboGears2 Pluggable Applications
 
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)
 
DRYing Up Rails Views and Controllers
DRYing Up Rails Views and ControllersDRYing Up Rails Views and Controllers
DRYing Up Rails Views and Controllers
 
Ruby on Rails - Introduction
Ruby on Rails - IntroductionRuby on Rails - Introduction
Ruby on Rails - Introduction
 
OSDC 2009 Rails Turtorial
OSDC 2009 Rails TurtorialOSDC 2009 Rails Turtorial
OSDC 2009 Rails Turtorial
 
Implement rich snippets in your webshop
Implement rich snippets in your webshopImplement rich snippets in your webshop
Implement rich snippets in your webshop
 
Bangla html
Bangla htmlBangla html
Bangla html
 
Rails 4.0
Rails 4.0Rails 4.0
Rails 4.0
 
Use Symfony2 components inside WordPress
Use Symfony2 components inside WordPress Use Symfony2 components inside WordPress
Use Symfony2 components inside WordPress
 
Система рендеринга в Magento
Система рендеринга в MagentoСистема рендеринга в Magento
Система рендеринга в Magento
 
What's new in Rails 2?
What's new in Rails 2?What's new in Rails 2?
What's new in Rails 2?
 
RubyBarCamp “Полезные gems и plugins”
RubyBarCamp “Полезные gems и plugins”RubyBarCamp “Полезные gems и plugins”
RubyBarCamp “Полезные gems и plugins”
 
Android L01 - Warm Up
Android L01 - Warm UpAndroid L01 - Warm Up
Android L01 - Warm Up
 
Building Potent WordPress Websites
Building Potent WordPress WebsitesBuilding Potent WordPress Websites
Building Potent WordPress Websites
 

Dernier

+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)

From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivity
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024
 
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...
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
HTML Injection Attacks: Impact and Mitigation Strategies
HTML Injection Attacks: Impact and Mitigation StrategiesHTML Injection Attacks: Impact and Mitigation Strategies
HTML Injection Attacks: Impact and Mitigation Strategies
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
 
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
Manulife - Insurer Innovation Award 2024
Manulife - Insurer Innovation Award 2024Manulife - Insurer Innovation Award 2024
Manulife - Insurer Innovation Award 2024
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
 
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live StreamsTop 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a Fresher
 
+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...
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 
GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdf
 

You're Doing It Wrong

  • 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
  • 5. What makes them hard to test? • Scripts that live outside app • Often have network and file access • Often have output
  • 6. 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
  • 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, @out end
  • 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
  • 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. end end
  • 17. The Task is Nice and Skinny namespace :twitter do task :search => :environment do Alert.create_all_from_twitter_search end end
  • 18. 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
  • 19. should "print a message at the beginning" do Alert.create_all_from_twitter_search(@output) assert_match /Searching/i, @output.string end
  • 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
  • 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 %>
  • 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 end end <!-- 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 %>
  • 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 %>
  • 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.

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
  52. \n
  53. \n