2013 Armando Fox amp David Patterson all rights reserved 1 Dealing with Forms Creating a resource usually takes 2 interactions new Retrieve blank form create Submit filled form How to generatedisplay ID: 810200
Download The PPT/PDF document "Forms (Engineering Software as a Servic..." is the property of its rightful owner. Permission is granted to download and print the materials on this web site for personal, non-commercial use only, and to display it on your personal computer provided you do not modify the materials and that you retain all copyright notices contained in the materials. By downloading content from our website, you accept the terms of this agreement.
Slide1
Forms (Engineering Software as a Service §4.6)
© 2013 Armando Fox & David Patterson, all rights reserved
1
Slide2Dealing with Forms
Creating a resource usually takes 2 interactionsnew: Retrieve blank formcreate: Submit filled formHow to generate/display?How to get values filled in by user?What to “return” (render)?2
Slide3Rails Cookery #3To create a new
submittable form: Identify the action that serves the form itself Identify the action that receives submission Create routes, actions, views for eachForm elements’ name attributes will appear as keys in params[]Helpers provided for many common elements
3
Slide4Creating the FormAnatomy of a form in HTML
the action and method attributes (i.e., the route)only named form inputs will be submittedGenerating the form in Railsoften can use URI helper for action, since it’s just the URI part of a route (still need method)form field helpers (see api.rubyonrails.org) generate conveniently-named form inputshttp://pastebin.com/k8Y49EhEhttp://pastebin.com/3dGWsSq84
Slide55
END
Slide6%form{:action =>
movies_path
,
:method => :post}
%form{:action => '/movies',
:method => 'post'}
All of the above
=
form_tag
movies_path
do
... end
☐
☐
☐
☐
6
Which of these would be valid for generating the form that, when submitted, would call the Create New Movie action?
Slide77
END
Slide8Redirection, the Flash and the Session(Engineering Software as a Service §4.7)
© 2013 Armando Fox & David Patterson, all rights reserved
8
Slide9Receiving the FormA neat trick: use debugger to inspect what’
s going onstart with rails server --debuggerinsert debugger where you want to stop details & command summary: ESaaS §4.7NOTE: params[:movie] is a hash, because of the way we named form fieldsConveniently, just what Movie.create! wants 9
Slide10What View Should Be Rendered for Create
Action?Idiom: redirect user to a more useful pagee.g., list of movies, if create is successfule.g., New Movie form, if unsuccessfulRedirect triggers a whole new HTTP requestHow to inform user why they were redirected?Solution: flash[]—quacks like a hash that persists until end of next requestflash[:notice] conventionally for informationflash[:warning] conventionally for “errors”10
Slide11Flash & Session
session[]: like a hash that persists foreverreset_session nukes the whole thingsession.delete(:some_key), like a hashBy default, cookies store entire contents of session & flashAlternative: store Rails sessions in DB table(Search “rails session use database table”)Another alternative: store sessions in a “NoSQL” storage system, like memcached
11
Slide1212
END
Slide13True - but
a bad idea!
False, because you
can’
t
put arbitrary objects into a hash
False, because
session[]
isn’
t
really a hash, it just quacks like one
True - knock
yourself out!
☐
☐
☐
☐
13
Ben
Bitdiddle
says:
“
You can put arbitrary objects (not just
“
simple
”
ones like
ints
and strings) into the
session[]
.
”
What do you think?
Slide1414
END
Slide15AdministriviaGet account for “public projects” on PivotalTracker.com,
add me, TAPublic projects are freeDo not get 30 day evaluation accountGet account on CodeClimate.comProvides code analysisFree for an open source (OSS) repoSign in with your GitHub account15
Slide1616
END
Slide17Finishing CRUD(Engineering Software as a Service §4.8)
© 2013 Armando Fox & David Patterson, all rights reserved
17
Slide18Edit/Update Pair is Analogous to New/Create Pair
What’s the same?1st action retrieves form, 2nd action submits it“submit” uses redirect (to show action for movie) rather than rendering its own viewWhat’s different?Form should appear with existing values filled in: retrieve existing Movie firstForm action uses PUT rather than POSThttp://pastebin.com/VV8ekFcn
http://pastebin.com/0drjjxGa
18
Slide19Destroy is EasyRemember, destroy is an
instance methodFind the movie first...then destroy itSend user back to Index def destroy @movie = Movie.find(params[:id]) @movie.destroy flash[:notice] = "Movie '#{@movie.title}' deleted." redirect_to movies_path end 19
Slide2020
END
Slide21Only this request and the next request
Only this
request - once
the view is rendered, the variable is reset to nil
It depends on whether the instance variable was declared stati
c
This request and all subsequent requests
☐
☐
☐
☐
21
If you set an instance variable in a controller method, its value will be retained for how long?
Slide2222
END
Slide23Fallacies, Pitfalls, and Perspectives on SaaS-on-Rails
(Engineering Software as a Service §4.9 - 4.11)
© 2013 Armando Fox & David Patterson, all rights reserved
23
Slide24Fat Controllers & Fat Views
Really easy to fall into “fat controllers” trapController is first place touched in your code Temptation: start coding in controller methodFat views“All I need is this for-loop”“....and this extra code to sort the list of movies differently”“...and this conditional, in case user is not logged in”No! That’s for model, controller, helpers24
Slide25Designing for Service-Oriented Architecture
A benefit of thin controllers & views: easy to retarget your app to SOATypically, SOA calls will expect XML or JSON (JavaScript Object Notation, looks like nested hashes) instead of HTMLA trivial controller change accomplishes thishttp://pastebin.com/bT16LhJ425
Slide2626
END
Slide27Only (b)
Only (b) and (c)
Only (a) and (c)
Only (a) and (b)
☐
☐
☐
☐
27
Which steps are ALWAYS required when adding a new action 'foo' to the Movie model of a Rails app:
(a) Ensure there is a template to render in
app/views/movies/
foo.html.haml
(or
.
html.erb
,
etc
)
(b) Ensure a route exists in
config
/
routes.rb
(c) Implement helper method to generate necessary route-helper URIs
Slide2828
END
Slide29Introducing Cucumber & Capybara
(Engineering Software as a Service §7.6)
29
© 2013 Armando Fox & David Patterson, all rights reserved
Slide30User Stories => Acceptance Tests?
Wouldn’t it be great to automatically map 3x5 card user stories into tests for user to decide if accept the app?How would you match the English text to test code?How could you run the tests without a human in the loop to perform the actions?
30
Slide31Cucumber: Big IdeaTests from customer-friendly user stories
Acceptance: ensure satisfied customerIntegration: ensure interfaces between modules consistent assumptions, communicate correctly Cucumber meets halfway between customer and developer User stories are not code, so clear to customer and can be used to reach agreement Also not completely freeform, so can connect to real tests
31
Slide32Example User Story
Feature: User can manually add movieScenario: Add a movie Given I am on the RottenPotatoes home page When I follow "Add new movie" Then I should be on the Create New Movie page When I fill in "Title" with "Men In Black" And I select "PG-13" from "Rating" And I press "Save Changes" Then I should be on the RottenPotatoes home page And I should see "Men In Black"
32
3 to 8 Steps / Scenario
≥1 Scenarios / Feature
1 Feature
Slide33Cucumber User Story, Feature, and Steps
User story: refers to single feature Feature: ≥1 scenarios that show different ways a feature is used Keywords Feature and Scenario identify respective componentsKept in .feature filesScenario: 3 - 8 steps that describe scenarioStep definitions: Ruby code to test stepsKept in X_controller.rb files
33
Slide345 Step Keywords
Given steps represent state of world before event: preconditions When steps represent event e.g., simulate user pushing a button Then steps represent expected postconditions; check if true/ 5. And & But extend previous step
34
Slide35Steps => Step Definitions via Regular Expressions
Regexes match English phrases in steps of scenarios to step definitions!Given /^(?:|I )am on the (.+)$/“I am on the Rotten Potatoes home page”Step definitions (Ruby code) likely use captured string“Rotten Potatoes home page”
35
Slide36More on “Cuke”
Need to install Cucumber GemJust for test and development environment, not for production environmentWhen Cucumber installed, it creates commonly used step definitionsNeed a test database to run appThen edit .features file to add features
36
Slide37Fake User to Try Scenarios?Need tool that pretends to be the user
to follow scenarios of user storiesCapybara simulates browserCan interact with app to receive pagesParse the HTMLSubmit forms as a user would
37
Slide3838
END
Slide39A Feature has one or more Scenarios, which are composed typically of 3 to 8 Steps
Steps use
Given
for current state,
When
for actions, and
Then
for consequences of actions
Cucumber matches step definitions to scenario steps using regexes, and Capybara pretends to be
a user
that interacts with
the SaaS
app
accordingly
Step definitions are in Ruby, and are similar to method calls, while steps are in English and are similar to method definitions
39
Which is FALSE about Cucumber and Capybara?
1.
2.
3.
4.
Slide4040
END
Slide41Running Cucumber and Capybara
(Engineering Software as a Service §7.7)
41
© 2013 Armando Fox & David Patterson, all rights reserved
Slide42Red-Yellow-Green Analysis
Cucumber colors stepsGreen for passingYellow for not yet implementedRed for failing (then following steps are Blue)Goal: Make all steps green for pass (Hence green vegetable for name of tool)
42
Slide43DemoAdd feature to cover existing functionality
Note: This example is doing it in wrong order – should write tests firstJust done for pedagogic reasons(Or can look at screencast: http://vimeo.com/34754747)
43
Slide4444
END
Slide45Enhancing Rotten Potatoes Again(Engineering Software as a Service §7.8)
45
© 2013 Armando Fox & David Patterson, all rights reserved
Slide46Add a Real New
Feature?What if we add something harder?e.g., includes form to fill ine.g., needs a User Interfacee.g., needs to add route to connect view to controllere.g., includes both a happy path and a sad path
46
Slide47Integrated with The Movie Database (TMDb)
New Feature: Populate from TMDb, versus enter information by handNeed to add ability to search TMDb from Rotten Potatoes home pageNeed LoFi UI and Storyboard
47
Slide48Storyboard TMDb
Figure 7.6 ofEngineering Software as aService
48
Slide49Search TMDb User Story
(Fig. 7.7 ESAAS)Feature: User can add movie by searching in The Movie Database (TMDb) As a movie fan So that I can add new movies without manual tedium I want to add movies by looking up their details in TMDbScenario: Try to add nonexistent movie (sad path) Given I am on the RottenPotatoes home page Then I should see "Search TMDb for a movie" When I fill in "Search Terms" with "Movie That Does Not Exist" And I press "Search TMDb" Then I should be on the RottenPotatoes home page And I should see "'Movie That Does Not Exist' was not found in TMDb."
49
Slide50Haml for Search TMDb
Page(Fig. 7.8 ESAAS)-# add to end of app/views/movies/index.html.haml:%h1 Search TMDb for a movie= form_tag :action => 'search_tmdb' do %label{:for => 'search_terms'} Search Terms = text_field_tag
'
search_terms
'
=
submit_tag
'Search
TMDb
'
50
http://pastebin/
18yYBVbC
Slide51Haml Expansion Last Two Lines
This Haml: = text_field_tag 'search_terms' = submit_tag 'Search TMDb’Turns into this HTML:<label for='search_terms'>Search Terms</label><input id="search_terms" name="search_terms" type="text" />for attribute of label tag matches
id
attribute of
input
tag, from
text_field_tag
helper
(above)
51
Slide52Try Cucumber?If try Cucumber, it fails
Missing the routeAlso MoviesController#search_tmdb is controller action that should receive form, yet not in movies_controller.rbShould use Test Driven Development (future lecture) to implement method search_tmdbInstead, to finish sad path, add fake controller method that always fails
52
Slide53Trigger Fake Controller When Form is POSTed
(Fig. 7.9)# add to routes.rb, just before or just after 'resources :movies' :# Route that posts 'Search TMDb' formpost '/movies/search_tmdb'
53
http://pastebin/
FrfkF6pd
Slide54Fake Controller Method: Will Fail Finding Movie
(Fig. 7.9)# add to movies_controller.rb, anywhere inside# 'class MoviesController < ApplicationController':def search_tmdb # hardwired to simulate failure flash[:warning] = "'#{params[:search_terms]}' was not found in TMDb." redirect_to movies_pathend
54
http:/pastebin/
smwxv70i
Slide5555
END
Slide5656
Which statement is TRUE?
Usually you code the sad paths first
A sad path can pass without having code written needed to make a happy path pass
None of the above is true
Usually you complete the Behavior Driven Design phase with Cucumber before starting the Test Driven Development phase with
RSpec
1.
2.
3.
4.
Slide5757
END
Slide58Running Rotten Potatoes Again(Engineering Software as a Service §7.8)
58
© 2013 Armando Fox & David Patterson, all rights reserved
Slide59DemoAdd feature to search for movie in
TMDbNote: This will be a sad path, in that won’t find itWill use fake method(until future when implement it using TDD)(Or can look at screencast: http://vimeo.com/34754766)
59
Slide60Happy Path of TMDbFind an existing movie, should return to Rotten Potatoes home page
But some steps same on sad path and happy pathHow to make it DRY?Background means steps performed before each scenario
60
Slide61TMDb w/2 Scenarios: Background (Fig. 7.10)
Feature: User can add movie by searching for it in The Movie Database (TMDb) As a movie fan So that I can add new movies without manual tedium I want to add movies by looking up their details in TMDbBackground: Start from the Search form on the home page Given I am on the RottenPotatoes home page Then I should see "Search TMDb
for a movie”
Scenario: Try to add nonexistent movie (sad path)
When I fill in "Search Terms" with "Movie That Does Not Exist"
And I press "Search
TMDb
"
Then I should be on the
RottenPotatoes
home page
And I should see "'Movie That Does Not Exist' was not found in
TMDb
.”
Scenario: Try to add existing movie (happy path)
When I fill in "Search Terms" with "Inception"
And I press "Search
TMDb
"
Then I should be on the
RottenPotatoes
home page And I should see "Inception”
61
http://pastebin/
icQGrYCV
Slide62Cucumber SummaryNew feature => UI for feature, write new step definitions, even write new methods before Cucumber can color steps green
Usually do happy paths firstBackground lets us DRY out scenarios of same featureBDD/Cucumber test behavior; TDD/RSpec in folllowing chapter is how write methods to make all scenarios pass
62
Slide6363
END
Slide64And in ConclusionCucumber –
“magically” maps 3x5 card user stories onto acceptance tests and integration tests for the application
64