diff --git a/Gemfile.lock b/Gemfile.lock index a3f75cb..851e078 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -30,7 +30,7 @@ GEM sprockets arel (4.0.2) atomic (1.1.15) - bookingit (0.4.1) + bookingit (0.4.2) gli mustache redcarpet (= 3.1.1) diff --git a/README.md b/README.md index b4ed7d6..34a52c9 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ This is the source of http://angular-rails.com. To build it, you'll need to do 1. `bundle install` or `gem install bookingit` to install the bookingit gem 1. `git clone https://github.com/davetron5000/receta git_repos/receta` to clone the repository containing the source code examples in the book 1. `createuser -d receta` to create a new PostgreSQL user as required by receta/config/database.yml -1. `pushd git_repos/receta && bundle install && popd` to install all gems that are required for the `receta` project +1. ``pushd git_repos/receta; bundle install; for remote in `git branch -r | grep -v "master" | grep -v "HEAD" | awk -F "/" '{print $2}'`; do git checkout $remote; done; git checkout master; popd`` to set up the sub-repository and install all gems that are required for the `receta` project 1. `bookingit build` to generate the HTML and CSS for the book Once this is done, open `book/index.html` in your browser. Whenever you change something, re-run `bookingit build`. diff --git a/crud_recipe.md b/crud_recipe.md index bfefcf9..b98206b 100644 --- a/crud_recipe.md +++ b/crud_recipe.md @@ -22,13 +22,13 @@ To make it work, we'll need to: First, we'll add some tests for our controller to get started: - git://receta.git/spec/controllers/recipes_controller_spec.rb#..back-end-crud + git://receta.git/spec/controllers/recipes_controller_spec.rb#..8e3a799 This is nothing but the happy path, mostly to speed us along here. Now, let's make these tests pass: - git://receta.git/app/controllers/recipes_controller.rb#..back-end-crud + git://receta.git/app/controllers/recipes_controller.rb#..8e3a799 You'll notice that we are skipping the authenticity token verification. While there is a way to insert the one that Rails generates into all HTTP requests, @@ -38,7 +38,7 @@ to generate one, so we have to skip the check for this. Don't forget to add the routes for the new actions: - git://receta.git/config/routes.rb#..back-end-crud + git://receta.git/config/routes.rb#..8e3a799 Back to our test, everything seems to be working: @@ -58,7 +58,7 @@ need to setup the controller so that there's no `recipeId` in the URL, and no ex Once we've changed `setupController()` accordingly, all we need to do is setup expectations of the HTTP calls to our backend, and then call the functions on `scope` that we'll need. - git://receta.git/spec/javascripts/controllers/RecipeController_spec.coffee#..front-end-crud + git://receta.git/spec/javascripts/controllers/RecipeController_spec.coffee#..b788ed9 You'll notice that `save()` is handling both creating a new recipe and updating an existing one. This will make it easier to re-use our view for both purposes, since the “Save” button we'll create can just call `save()`, allowing the controller to work @@ -73,7 +73,7 @@ To make this test pass, we'll need to: Let's do it: - git://receta.git/app/assets/javascripts/controllers/RecipeController.coffee#front-end-crud + git://receta.git/app/assets/javascripts/controllers/RecipeController.coffee#..b788ed9 You'll notice we made a `create()` method when setting up our `Recipe` resource. By default, Angular allows both `recipe.$save()` and `Recipe.save(recipe)`, the latter being what we'd use to create a new recipe. Since Rails wants a `POST` for @@ -99,7 +99,7 @@ by `RecipeController` and a new view, `form.html`. First, let's set up the routes in `app.coffee`: - git://receta.git/app/assets/javascripts/app.coffee#..crud-views + git://receta.git/app/assets/javascripts/app.coffee#..efdc8fe Next, we'll create `form.html`: @@ -107,7 +107,7 @@ Next, we'll create `form.html`: Now, we'll need to add a link to create a recipe as well as one to edit in `index.html`: - git://receta.git/app/assets/javascripts/templates/index.html#..crud-views + git://receta.git/app/assets/javascripts/templates/index.html#..efdc8fe These links require new functions called `newRecipe()` and `edit()`, which we'll add to `RecipesController.coffee`: @@ -115,7 +115,7 @@ These links require new functions called `newRecipe()` and `edit()`, which we'll And lastly, we'll need links to edit and delete a recipe in `show.html`: - git://receta.git/app/assets/javascripts/templates/show.html#..crud-views + git://receta.git/app/assets/javascripts/templates/show.html#..efdc8fe Whew! Let's see if it all works by re-running our browser-based test: diff --git a/find_and_browse.md b/find_and_browse.md index 61d3532..e9f41f3 100644 --- a/find_and_browse.md +++ b/find_and_browse.md @@ -100,14 +100,14 @@ Fortunately, the gem `angular-rails-templates` exists to do just that. Let's add it to our `Gemfile`: - git://receta.git/Gemfile#..add-angular-templates + git://receta.git/Gemfile#..7ec4c7d Running `bundle install` will download the gem for us. In addition to this gem, we're also going to need the `angular-route` module, which enables the routing we saw above. We'll add it to our `Bowerfile` first: - git://receta.git/Bowerfile#..add-angular-route + git://receta.git/Bowerfile#..9220c75 Once we run `rake bower:install` to download `angular-route` and `angular-rails-templates`, we'll need to reference them in our `application.js` file so they're available to the app (note that older version of `angular-rails-templates` did not require referencing in the `application.js` file, so be sure you are on the latest version): @@ -198,7 +198,7 @@ Now, let's look at our view. We need to bind the value of the search field to a search, which we must trigger from the “Search” button. We also will remove our duplicated markup in favor of markup for one result, wrapped in an `ng-repeat` directive. - git://receta.git/app/assets/javascripts/templates/index.html#..front-end-canned-search + git://receta.git/app/assets/javascripts/templates/index.html#..c1e478a Note that we're also using `ng-if` to hide the results section entirely if there aren't any results. @@ -321,7 +321,7 @@ Since this is the first real code we're writing in Angular, this is where we'll `teaspoon`, which is a test runner for JavaScript that uses the asset pipeline, Jasmine, and PhantomJS. We'll add teaspoon and PhantomJS to our `Gemfile`: - git://receta.git/Gemfile#setup-teaspoon^1..setup-teaspoon + git://receta.git/Gemfile#cbdc80a^1..cbdc80a Once we run `bundle install`, we need to bootstrap teaspoon, which can be done with the Rails generator it includes: @@ -350,16 +350,16 @@ the best thing to do is keep adding files to `config/initializers/assets.rb` unt Back to the task at hand, we're also going to need two more Angular modules. We need `angular-mocks` to help with testing and `angular-resource` to implement the AJAX calls. First, we add them to `Bowerfile`: - git://receta.git/Bowerfile#setup-teaspoon^1..setup-teaspoon + git://receta.git/Bowerfile#cbdc80a^1..cbdc80a Once we run `rake bower:install` to download them, we need to add `angular-resource` to `application.js`: - git://receta.git/app/assets/javascripts/application.js#setup-teaspoon^1..setup-teaspoon + git://receta.git/app/assets/javascripts/application.js#cbdc80a^1..cbdc80a Finally, we'll need to include `ngResource`—the module provided by `angular-resource`—in our `app.coffee`. While we're there, we'll inject `$resource`—the function bundled in the `ngResource` module—into our controller: - git://receta.git/app/assets/javascripts/app.coffee#setup-teaspoon^1..setup-teaspoon + git://receta.git/app/assets/javascripts/app.coffee#cbdc80a^1..cbdc80a Since `angular-mocks` is only needed for tests, we *won't* put it in `application.js`. Teaspoon allows Sprockets directives in our test files, and it generated `spec/javascripts/spec_helper.coffee` for us, which is included in all tests. We'll add this @@ -531,7 +531,7 @@ The test is failing just how we'd expect: there are no HTTP requests to flush, ` The `angular-resource` module makes this very simple. We create a resource for our recipes, and then call the `query()` method (generated for us by Angular). - git://receta.git/app/assets/javascripts/app.coffee#angular-controller-test-pass^1..angular-controller-test-pass + git://receta.git/app/assets/javascripts/app.coffee#863c5fb^1..863c5fb Now, let's re-run our tests: @@ -548,7 +548,7 @@ We can now remove `recipes` from `app.coffee` since we're talking to the real ba is relying on that data being there to verify the feature is working. All we have to do is populate the database with the same data. We'll create it in a `before` block. - git://receta.git/spec/features/search_spec.rb#backend-integrated^1..backend-integrated + git://receta.git/spec/features/search_spec.rb#66140a9^1..66140a9 Now, if everything's working, our test should still pass. @@ -567,7 +567,7 @@ good refactor. First, we'll remove the controller from `app.coffee`, but notice that we leave in the module declaration: - git://receta.git/app/assets/javascripts/app.coffee#extract-controller-to-file^1..extract-controller-to-file + git://receta.git/app/assets/javascripts/app.coffee#83688a3^1..83688a3 We'll place the controller code in `app/assets/javascripts/controllers/RecipesController.coffee`, and notice that we have _repeated_ the module declaration (or so it seems): diff --git a/view_recipe.md b/view_recipe.md index 86ddc93..e120518 100644 --- a/view_recipe.md +++ b/view_recipe.md @@ -30,7 +30,7 @@ Generally, what we need to do here is: First, we'll update our Angular app config to route `/recipes/:recipeId` to the yet-to-be-created `RecipeController`: - git://receta.git/app/assets/javascripts/app.coffee#..add-recipe-controller + git://receta.git/app/assets/javascripts/app.coffee#..13ec847 Now, let's create a bare-bones version of our controller: @@ -47,7 +47,7 @@ What `RecipeController` needs to do is: Lets get the happy path working first: - git://receta.git/spec/javascripts/controllers/RecipeController_spec.coffee#..recipe-controller-test + git://receta.git/spec/javascripts/controllers/RecipeController_spec.coffee#..62feecc This is similar to what we had in `RecipesController_spec.coffee`. Because the HTTP call to our backend happens on controller startup, we create a @@ -67,7 +67,7 @@ Let's make it pass. We'll use Angular's `$resource` service to create the same resource we did in `RecipesController`, but use the `get` method, which does what we want. - git://receta.git/app/assets/javascripts/controllers/RecipeController.coffee#..recipe-controller-test-passes + git://receta.git/app/assets/javascripts/controllers/RecipeController.coffee#..952c819 Now, we see if this makes our tests pass: @@ -87,7 +87,7 @@ them in our views. `angular-flash` is that component, so let's install it. First, we add it to `Bowerfile`: - git://receta.git/Bowerfile#..install-angular-flash + git://receta.git/Bowerfile#..df5539b To make sure the asset pipeline picks up this new dependency, we'll need to add it to `application.js` as well: @@ -101,7 +101,7 @@ Finally, we add it as a module dependency to our app. `angular-flash` comes wit two modules, one for the flash data itself, and another for the view components. - git://receta.git/app/assets/javascripts/app.coffee#..install-angular-flash + git://receta.git/app/assets/javascripts/app.coffee#..df5539b We'll see how the view components work a bit later, but for now, our controller can depend on a component called `flash`. `flash` allows us to set @@ -110,7 +110,7 @@ errors, warnings, informational messages, and success messages. Back to our test, we want to assert that the flash receives an error message that the recipe couldn't be found. - git://receta.git/spec/javascripts/controllers/RecipeController_spec.coffee#..test-recipe-controller-for-flash + git://receta.git/spec/javascripts/controllers/RecipeController_spec.coffee#..8aa6cf7 Notice that we're taking advantage of Angular's alternate dependency injection naming convention. We want our test to use an object called @@ -127,7 +127,7 @@ Now, when we run the test, we should see a simple expectation failure on the mes With a clearly failing test, we just need to add the flash as a dependency, and use it. - git://receta.git/app/assets/javascripts/controllers/RecipeController.coffee#..test-for-flash-passes + git://receta.git/app/assets/javascripts/controllers/RecipeController.coffee#..b9ee91e We add `flash` to the list of injected dependencies, and then set the error message in our failure callback. Sure enough, the test passes: @@ -142,15 +142,15 @@ and `show`, so what we need to do here is implement `show`. First, let's add the new route to `config/routes.rb`: - git://receta.git/config/routes.rb#..failing-recipe-show + git://receta.git/config/routes.rb#..323798b We'll add an empty `show` method to the controller as well: - git://receta.git/app/controllers/recipes_controller.rb#..failing-recipe-show + git://receta.git/app/controllers/recipes_controller.rb#..323798b Finally, we'll write tests for when the recipe exists and for when it doesn't: - git://receta.git/spec/controllers/recipes_controller_spec.rb#..failing-recipe-show + git://receta.git/spec/controllers/recipes_controller_spec.rb#..323798b This should result in a failing test, which it does: @@ -158,7 +158,7 @@ This should result in a failing test, which it does: To make this pass, we'll fetch the recipe: - git://receta.git/app/controllers/recipes_controller.rb#..recipe-show-passes + git://receta.git/app/controllers/recipes_controller.rb#..5764b6e and implement a JBuilder view that uses our existing `_recipe.json.jbuilder` partial: @@ -170,7 +170,7 @@ To handle the case of a non-existent recipe, we'll let the `rescue_from` in `ApplicationController` to handle that. This way, we never have to worry about translating this error into a 404 again. - git://receta.git/app/controllers/application_controller.rb#..recipe-show-passes + git://receta.git/app/controllers/application_controller.rb#..5764b6e Now, everything passes! @@ -199,14 +199,14 @@ as actually build out the “show” view. First, we'll change the `a`: - git://receta.git/app/assets/javascripts/templates/index.html#..view-integrated + git://receta.git/app/assets/javascripts/templates/index.html#..62a1e1d Notice that we removed the argument to `href`, which will keep the browser from changing its location and reloading our view. Instead, we used `ng-click` to trigger the `view()` method that we'll now add to `RecipesController`: - git://receta.git/app/assets/javascripts/controllers/RecipesController.coffee#..view-integrated + git://receta.git/app/assets/javascripts/controllers/RecipesController.coffee#..62a1e1d All that's left is to create the view in `show.html`: @@ -214,7 +214,7 @@ All that's left is to create the view in `show.html`: We'll also add a method to make the “Back” button work: - git://receta.git/app/assets/javascripts/controllers/RecipeController.coffee#..add-back-button + git://receta.git/app/assets/javascripts/controllers/RecipeController.coffee#..480fcfa Now, everything works: @@ -247,7 +247,7 @@ complex logic around the flash, and its message, a test would be more useful, bu First, we'll add the necessary markup to `show.html`: - git://receta.git/app/assets/javascripts/templates/show.html#..integrate-flash + git://receta.git/app/assets/javascripts/templates/show.html#..db53af6 Our `article` tag has three special attributes, provided by `angular-flash`: @@ -258,7 +258,7 @@ Our `article` tag has three special attributes, provided by `angular-flash`: The second thing we need to do is to configure `angular-flash` so that it knows about the various alert classes that Bootstrap provides. We do this in the app config in `app.coffee`: - git://receta.git/app/assets/javascripts/app.coffee#..integrate-flash + git://receta.git/app/assets/javascripts/app.coffee#..db53af6 What this configuration means is that if there is, for example, a value in `flash.error`, `angular-flash` will add the class `alert-danger` to the flash element. Since we also configured that element to add `alert` to *any* flash message, our markup