-
Notifications
You must be signed in to change notification settings - Fork 9
Teaching Notes
#Week 6: Rails III (Advanced Topics)
- TDD using Guard and focus on Integration tests
- Bootstrap + SASS (from the beginning)
- Pagination (Kaminari / Kaminari - Bootstrap)
- Mailing (ActionMailer/Letter Opener)
- Search (WebSolr LIKE-based)
- Authentication (Sorcery)
- File Upload (CarrierWave)
- Accepts Nesteded Atttributes + Nested Form + Nested Validation
- CounterCache
#App: CrowdFunder (a Kickstarter clone)
The app will allow users to pledge against existing projects or create their own project. Visitors will be able to search for projects. Project owners will be able to upload images to their project.
Students will be able to use a variety of gems, create applications that can send and receive email, as well as have an understanding of a search function.
##Models
-
Project(title, teaser, description, user) -
Reward(project, amount, description) -
User(first, last, email, password, etc) -
Pledge(user, project, amount, reward) -
Image(project)
##Prerequisites
-
pgrequires:- Postgres.app on mac
- Postgres Ubuntu on Ubuntu
-
capybara-webkitrequires:- Qt 4.8.4 installed (download mpkg installer from their site directly, no need for brew)
- Check to make sure you can run qmake from command line
##Workflow / Commits
-
Setup app with test/unit, factory girl, capybara, guard and pg
Commits
4b9c24be3d- Initial Commitd64a32c02d- Initial dev & test environment setup5bd701aa91- Disable fixtures for Test::Unit
Gemfilegem 'pg' group :tools do gem 'rb-fsevent', :require => false # mac gem 'rb-inotify', :require => false # linux gem 'rb-fchange', :require => false # windows gem 'guard-test' gem 'guard-livereload' end group :test do gem "factory_girl_rails" gem "database_cleaner" gem "capybara" gem "capybara-webkit" endRun
bundle installto get all the gems aboveSetup
database.ymlwith correct database info:database.ymldevelopment: adapter: postgresql database: crowdfunder_dev host: localhost # Warning: The database defined as "test" will be erased and # re-generated from your development database when you run "rake". # Do not set this db to the same as development or production. test: adapter: postgresql database: crowdfunder_test host: localhostRun
bundle exec guard initthenbundle exec guardin main terminal tabRun
rake db:createto create the dev and test databasesChange app to use
FactoryGirlinstead of fixturesconfig/application.rbconfig.generators do |g| g.test_framework :test_unit, :fixture => false endRemove
fixtures :allfromtest/test_helper.rb -
Install sorcery:
6226b0a762- Add user modelgem 'sorcery'Run:
rails generate sorcery:installModify migration to remove username and set email to null false Also add
first_nameandlast_namet.string :first_name t.string :last_name t.string :email, :default => nil, :null => falseDon't forget to migrate
rake db:migrate[ COMMIT ]
-
Generate project model:
7e5d1be755- Generate project model, Seed some datarails generate model project title teaser user:references description:text goal:integeropen migration to show the references statement and
t.references user==t.integer user_id(how they both create integer column)Make sure to update
user.rbwithhas_many :projectsDon't forget to migrate
rake db:migrate[ COMMIT ]
-
Seed a user and some projects:
seeds.rbUser.destroy_all Project.destroy_all user = User.create!(first_name: "John", last_name: "Doe", email: "[email protected]", password: "jdoe111") 50.times do |i| project1 = user.projects.create!(title: "Project #{i}", teaser: "Teaser text #{i}", description: "description #{i}", goal: 13000) endshow
db:seedanddb:resetin list of rake tasks usingrake -Trake -T | grep dbwhy destroy first? B/C seeds does not clear
[ COMMIT ]
-
Project list page (with link_to project show page) (TDD: integration test)
c6ad4655a7- Listing projects - our first controller and actionrails generate(list of generators in app)generate factory
rails g factory_girl:model User rails g factory_girl:model Projecttest/factories/users.rbFactoryGirl.define do factory :user do first_name "Karl" last_name "Denninger" sequence(:email) {|n| "karl#{n}@example.com" } password "karl.is.king" end endtest/factories/projects.rbFactoryGirl.define do factory :project do user title "Wifi-enabled lamps!" teaser "How have we been able to survive without these?" description "Lorem ipsum... " goal 12000 end endMake sure you delete the old fixtures in
test/fixturesGenerate first integration test:
rails generate integration_test project_flowsAdd this to
/test/test_helper.rb, this allows us to usecapybarawithTest::Unitclass ActionDispatch::IntegrationTest # Make the Capybara DSL available in all integration tests include Capybara::DSL endAdd code to visit
/projectsand assert contentvisit '/projects' assert page.has_content?('Listing projects')Witness error from guard
ActionController::RoutingError: No route matches [GET] "/projects"After defining
resources :projectsin routes, witness next error:ActionController::RoutingError: uninitialized constant ProjectsControllerGenerate projects controller, index action and:
-
Controller:
@projects = Project.all -
Templates:
index.html.erb: template listing all projects in UL; and expected h1 title
[ COMMIT ]
-
-
Our first browser experience (
rails s,open)d7b7f996ac- Pretty up the layout- Project Page
- Pretty it up by adding bootstrap sass gem to the project
Gemfilegroup :assets do gem 'sass-rails', '~> 3.2.3' gem 'bootstrap-sass', '~> 2.2.2.0' gem 'uglifier', '>= 1.0.3' end- Add _nav partial with Home and Projects links
/app/views/layouts/shared/_nav.html.erb<div class="navbar navbar-fixed-top"> <div class="navbar-inner"> <div class="container"> <a class="brand" href="#">CrowdFunder</a> <div class="nav-collapse collapse"> <ul class="nav"> <li class="<%= 'active' if current_page? root_path %>"> <%= link_to 'Home', :root %> </li> <li class="<%= 'active' if current_page? projects_path %>"> <%= link_to 'Projects', :projects %> </li> </ul> </div><!--/.nav-collapse --> </div> </div> </div>- Write "navigation" test case in ProjectFlowsTest file
/test/integration/project_flows_test.rbtest "navigation" do visit "/" assert_equal root_path, current_path # The home nav element should be active assert_equal "Home", find('.navbar ul li.active a').text find('.navbar ul').click_link('Projects') # more specific: assert_equal projects_path, current_path # The projects nav element should be active assert_equal "Projects", find('.navbar ul li.active a').text end- By the end, you get: Project Page -- Bootstraped
[ COMMIT ]
-
Project show page:
f167b8c644- Project details page - setup- Student driven
- Show page must at min have project title and user name for now
[ COMMIT ]
-
Fix bug on navigation (the project header does not highlight when you're on the
showpage for project)b5b77f53a7- Fix Bug #1- Student driven
- Emphasis on writing the test case first
[ COMMIT ]
-
Sorcery - user registration
6e0bcc979f- User signup- Define Test for user registration and failed registration
- Update nav with Sign Up and Logout buttons based on state
- DONT handle form errors (intentional bug)
- Presence validations on User password/name fields
[ COMMIT ]
-
Fix bug with registration error upon failed registration
6cc4f088ae- Fix Bug #2- Look for text upon failure
- Add
form.objects.errors.full_messagesas alert tonew.html
[ COMMIT ]
-
Login and logout
742fa33e34- Login and Logout functionality-
Implement Login first
-
Eventually get error in GUARD (test case) that username column doesn't exist
-
Update sorcery to use email for auth instead of username
-
Write logout test
-
Update logout button in _nav from # to destroy sessions action
-
Notice error:
No route matches [GET] "/session" -
Explain that the default capybara driver does not use JS. Use
capybara_webkitfor:webkit javascript_driver -
Explain headless browser
-
Couple of changes to
Gemfileandtest_helper.rb(including addition ofdatabase_cleaner.rb) -
Use the
javascript_driverfor just that one (logout) test not all of them -
Explain that we could just make it the default but it would be slower to run
-
Expect alert on failed login attempt but don't get any
-
Update
application.html.erbto includeflash[:alert]
[ COMMIT ]
-
-
Ability to pledge for a project
2e8e71f48c- Create pledge model-
Generate pledge model:
rails g model pledge user:references project:references amount:integer
[ COMMIT ]
-
-
Pledge creation flow
2aac32c453- Pledge creation workflow-
Generate integration test expecting 'Back This Project' button that:
- When clicked will be redirect to
new_user_pathfor unauthenticated user
- When clicked will be redirect to
-
Add button to projects#show labeled 'Back This Project'
Encounter issue:
<"/users/new"> expected but was <"/projects/1/pledges/new">.
Define sorcery
before_filterin pledges_controller:[ COMMIT ]
-
-
My/Projects
5f0459e096- My projects (CRUD)-
TDD built CRUD for my projects (no scaffolding)
rails g controller my/projects index new edit -
generate my/project_flows for TDD
-
update routes to remove auto-gen entries and add
:projectsunder namespace:my -
clean out functional(controller) test stubs
Note: for testing 404 page (when testing access restrictions),
-
Will see guard raise ActiveRecord::NotFoundException instead of display 404.html
-
change following settings in test.rb
consider_all_tests_local show_exceptions
[ COMMIT ]
-
-
Fix Nav issue (see comment for notes)
887f3aa075- Bug Fix - Nav statesBoth my/projects and projects controllers have controller_name == 'projects'
Instead of using
controller_name, we now use abefore_filterto set an instance variable@nav. This is more flexible but not the only way to solve this problem.[ COMMIT ]
-
Email project owner when their project is backed
57e628c51a- Email project owner when pledge made-
Generate mailer
rails g mailer user_mailer -
Explain
ActionMailer::Base.deliveriesfor testing -
Define
last_mailandreset_mailintest_helper, for integration tests -
Update pledge flows test case to expect
last_email
[ COMMIT ]
-
-
Pagination
4f1b23573c- Pagination on projects index page- Install and generate config (8 per page) for kaminari
- Update seeds file to create 50 projects (50.times)
- Update integration test to expect only X items
- Lastly, add the
kaminari-bootstrapgem so it looks better
[ COMMIT ]
-
Image uploads through Carrierwave
81a59bf119- Implement image upload for my projects-
Install
carrierwaveintoGemfilerails g model image project:references file -
add model validations and associations
rails g uploader Image rails g controller my/images -
nested resource in routes
-
Generate
my/image_flowstest case with 2 tests (success / fail) -
Before committing, update
.gitignoreto include/public/uploads/*
[ COMMIT ]
-
-
Ability to delete projects
3e45bd33f2- Ability to delete my project- Delete
link_towill have a:confirm - Talk about Rails UJS (unless covered before)
- How will
capybarabe able to handle confirm? - See
capybara-webkitREADME on github search for confirm and find driver-specific API
[ COMMIT ]
- Delete
-
Ability to search for projects
- Using LIKE base search
-
Some sort of AJAX functionality
- Discussion / Commenting on projects (new model)
- Deletion of images from index page
- Pledge creation (which can fail - ajax submission and feedback)
-
Visual polish
- Add images to
/projects - Cleanup
projects#indexandprojects#show - Bootstrap slideshow or lightbox/colorbox for images? jquery plugin
##Stuff not covered (To discuss):
- S3 storage w/ Fog
- Deployment
- Multiple asset manifest files (better understanding of the asset pipeline)
- SimpleForm or Formtastic for better output
- Quiet assets (minor)
- Feature / hotfix branches (good git workflows)