- Easy Internationalization for Your Rails App with BDD
- Easy Internationalization for Your Rails App with BDD, Part II
- Easy Internationalization for Your Rails App with BDD, Part III
- Easy Internationalization for Your Rails App with BDD, Part IV
Creating a Location.
In the first part, we built an application that lists locations in English and Spanish.
In this part we will create a new location, showing localization concerns along the way. Remember, we are using Cucumber and BDD to drive out our application.
Let’s write the scenario on how we would do that.
The scenario is pretty short, and does not mention any implementation details. Currently, When we run Cucumber it will run all the scenarios. We really don’t need to do that since we are only focusing on the
Create a new location scenario. Luckily, it’s easy to tell Cucumber to focus on just the “work in process” scenarios. Above the new scenario, add the
@wip tag. (wip = Work In Progress)
It should look like this now.
Excellent, now we can run Cucumber and just focus on the current scenario.
FAIL! As expected, Cucumber tells us that we have undefined scenarios. Let’s chip away at this scenario and get it green.
Copy the step definitions for undefined steps into the features/step_definitions/location_step.rb file.
Starting with the first step definition, we visit the new_location_path.
Running the scenario now yields the following output.
The “undefined local variable or method `new_location_path’?” tells us that we need to add a route. Open the routes.rb file in the /config folder and add the new route.
Now what happens when we run the test?
Of course, the action ‘new’ could not be found for LocationsController. Cucumber is guiding us in creating our Rails app. Let’s add that to the locations_controller.rb file in the /app/controllers folder.
OK, Cucumber, tell us what is happening now…
Another expected outcome, we need to create our view for the action. In the /app/views/locations folder create a new.html.erb file. In that we will create the form.
If I know my Rails and BDD, we should be through the first step.
Yup, the first step is passing. Time to focus on the second step. The code to satisfy that step sounds just like the step name (thank you, Capybara!)
Can you guess what Cucumber will tell us to do next?
Now we need to click the create button. Again, the Capybara helpers are our friend. In the locations_steps file, make the “When I press” step look like:
Let’s run the test.
We expected to see the content “Shiny location” in “InternationalizationnnLocationsnn”. Let’s look at it closely.
Why is it going to /locations? It should be going to /locations/create. It must be a routing issue, so open the routes.rb file and within the locale scope and add:
We can verify our routes look correct using
That looks right, so let’s run the scenario.
Really? The same error? Let’s look back at our routes. The first route in the file is the index action. The way routes work is the first match wins. Since both routes have the name of locations, the index action always wins. We have Two possible solutions. Move the create action route to the top or add
:via => get to the index action.
I like the latter. Let’s make the index action route look like:
Recheck the routes:
OK, only GET actions will call the index page. Our scenario should be happy, or at least, not complaining about routes any more.
Sure enough, there is a new error.
The action 'create' could not be found for LocationsController. You can see how using Cucumber to guide the design of a Rails application can get into a nice repeatable groove of creating the route, action, and view for a scenario.
Here, we forgot the C part of CRUD. Open the locations_controller and add the create method.
Let’s run the test.
Hmm. In the create method we redirect it to @locations. We need to add a route for that.
In the routes.rb file add:
Does that complete the scenario?
Nope, looks like we need to add the show action. Open the locations_controller.rb file and add:
I am sure it’ll work now.
Oops, seems we need to add a show.html.erb file. Create one in the /app/views/locations folder and add the code to display the location.
Yeah, it’s not real fancy, but we’re just getting the tests to pass.
Ready for a break?
La Creación de Nuevas Ubicaciones
The English (default) language scenario is passing, now it’s time to focus on Spanish. Create a new scenario in the /features/manage_locations.feature.
I bet you can guess what the output of running this scenario will be…
The first two steps are the same, so they pass with flying colors. However, our widgets are now named for the locale we are using (es) and Cucumber can’t find the. Remember the I18n.translate call? We’re using that again for the name field. Open the new.html.erb file in the views folder.
If we run the test now, both @wip scenarios will fail since we call the translate function and we haven’t supplied the translations. Let’s add those now.
In the /config/locales folder and open the en.yml file and add:
Don’t forget Spanish. Open the es.yml file and add:
I bet it can find the name field in both cases now.
Looks like we need to do the same for the create button. In the new.html.erb page we’ll change the submit button.
Of course, we have to add the button_html to the locales.
Are we done?
Yay! However, before we celebrate we have a couple of things to do. Remove the
@wip tags from the feature file and rerun the scenarios.
What?? On the third scenario it thinks the locale is
es since that’s what we set in the second scenario. In the English scenarios we need to add the locale to the scenarios.
Excelente! Todos son verdes.
In the next part of this series we will edit the locations.
You might have noticed that the first and second scenario were essentially identical. The same is true for the third and fourth scenarios. We can group them together with outlines.
We put place holder in the outline and the corresponding values are in the table.
The beauty of this is that if you want to add a test, for example for name validation, we can easily add it to the Examples as I’ve done below:
See you next time. Hasta luego!