Easy Internationalization for Your Rails App with BDD, Part II

John Ivanoff
John Ivanoff

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.

[gist id=”1699848″]

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.

[gist id=”1699838″]

Excellent, now we can run Cucumber and just focus on the current scenario.

[gist id=”1699852″]

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.

[gist id=”1699854″]

Starting with the first step definition, we visit the new_location_path.

[gist id=”1699857″]

Running the scenario now yields the following output.

[gist id=”1699864″]

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.

[gist id=”1699867″]

Now what happens when we run the test?

[gist id=”1699871″]

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.

[gist id=”1699878″]

OK, Cucumber, tell us what is happening now…

[gist id=”1699881″]

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.

[gist id=”1699886″]

If I know my Rails and BDD, we should be through the first step.

[gist id=”1699888″]

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

[gist id=”1699892″]

Can you guess what Cucumber will tell us to do next?

[gist id=”1699896″]

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:

[gist id=”1699898″]

Let’s run the test.

[gist id=”1699900″]

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:

[gist id=”1699904″]

We can verify our routes look correct using rake routes:

[gist id=”1699907″]

That looks right, so let’s run the scenario.

[gist id=”1699914″]

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:

[gist id=”1699917″]

Recheck the routes:

[gist id=”1699918″]

OK, only GET actions will call the index page. Our scenario should be happy, or at least, not complaining about routes any more.

[gist id=”1699919″]

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.

[gist id=”1699923″]

Let’s run the test.

[gist id=”1699926″]

Hmm. In the create method we redirect it to @locations. We need to add a route for that.
In the routes.rb file add:

[gist id=”1699927″]

Does that complete the scenario?

[gist id=”1699929″]

Nope, looks like we need to add the show action. Open the locations_controller.rb file and add:

[gist id=”1699931″]

I am sure it’ll work now.

[gist id=”1699933″]

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.

[gist id=”1699938″]

Yeah, it’s not real fancy, but we’re just getting the tests to pass.

[gist id=”1699941″]

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.

[gist id=”1699949″]

I bet you can guess what the output of running this scenario will be…

[gist id=”1699955″]

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.

[gist id=”1699959″]

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:

[gist id=”1699961″]

Don’t forget Spanish. Open the es.yml file and add:

[gist id=”1699963″]

I bet it can find the name field in both cases now.

[gist id=”1699967″]

Looks like we need to do the same for the create button. In the new.html.erb page we’ll change the submit button.

[gist id=”1699968″]

Of course, we have to add the button_html to the locales.
en.yml file:

[gist id=”1699970″]

es.yml file:

[gist id=”1699973″]

Are we done?

[gist id=”1699979″]

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.

[gist id=”1699984″]

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.

[gist id=”1699987″]

Fingers crossed…

[gist id=”1699993″]

Excelente! Todos son verdes.

In the next part of this series we will edit the locations.


Scenario Outlines.

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.

[gist id=”1700000″]

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:

[gist id=”1707923″]

See you next time. Hasta luego!