Easy Internationalization for Your Rails App with BDD, Part III
Editing A Location.
In the first part, we built an application that lists locations in English and Spanish. In the second part, we added the ability to create new locations in English and Spanish.
In this part we will edit a location, showing localization concerns along the way. Remember, we are using Cucumber and BDD to drive out our application.
Let’s write a scenario to do that.
Before we commit to that, let’s take a step back. At the end of Part II we refactored our scenarios into scenario outlines. We’ll write the scenario like that to save some refactoring later. We will also use the @wip tag so we can just concentrate on this test for now.
The example table holds the parameters for our scenarios. The parameters are the language, the original location name, the action to perform, and the label for the name field. The last parameter specifies the message displayed after the action completes.
Let’s add that to our /features/managing_locations.feature file. Run Cucumber and see what happens.
Not too bad. A couple of steps already pass. Cucumber is telling us what to do next. How would you “Update” the location “Name” to “New name”?
+ Go to a location’s page.
+ Click on the edit link.
+ Fill in the name field with our new location name.
+ Click the update button.
Sounds good, let’s write those steps.
Open up /features/stepdefinitions/locationssteps.rb and add those steps.
Does that make sense?
Since we created a location in an earlier step, we grab the first location. We also pass the locale. That will make the following route “/en/locations/1”. Thanks to Capybara the “Edit” link will get clicked. The form will get filled in. And the submit button will be clicked.
Think it’ll work? Let’s run Cucumber.
All right. Cucumber is guiding the next task: adding the edit link on the show page. Open up /app/views/locations/show.html.erb
Roll the dice.
We need to define the edit_location route. We can do that. Open up /config/routes.rb and, above the root route, add
That should do it. Cucumber, Let’er rip.
Huh? We need to add the edit action in the locations controller. Open the location controller file up and add that action
Second verse, same as the first. Rerun the test.
We need an edit page. Since our edit page and new page are the same we will combine them using partials. Make the form page and then include that partial in the new and edit pages. Extract the form from the new.html.erb file and paste it into the
In the new.html.erb, call the form partial.
The edit page looks very similar….
Let’s run the test and see what damage we’ve done.
We don’t see the update button.
According the the en.yml file the button will say Create. If we change that to Update then the test for Create will fail. The original form just had a <%= f.submit %> for the button and it knew when to say Create or Update. Let’s dig into the source code of rails and see how that works.
Check out the form helpers for the actionview around line 1064 it explains how that works. And, OMG, they tell us what to do when using i18n. Freakin’ awesome!
Now, update the en.yml file to reflect that.
Run the test.
WAIT! Look at what we did. We no longer have a .button_html in the en.yml file. Now, we’re saying that the helper for submit will say either Create for Post, otherwise it will say Update. That being said, we need to change the button in the form back to the default approach.
That feels cleaner.
_expected there to be content "location has changed" in "Internationalnnlocation 1nEditnn"_ HMMM…that doesn’t seem right. Why does it still say location 1? Let’s look at the test log file.
Open /log/test.log and look at the last few lines.
After the edit action, it’s routing to the show action. Routing issue! If you look at the last request Started PUT “/en/locations/1” for 127.0.0.1. It’s using the verb PUT to signify an update action. We have a route for /locations/:id and it goes to the show action. Since that route can use any verb, GET, PUT, or anything else, that route needs to respond to only a GET. Then we need to make a route for the update action that only responds to PUT.
Let’s open up the routes file.
Any bets? Will it pass? Roll the cucumber dice.
There we go. I was expecting this error. Let’s add the update action to the controller.
You know what to do next… rerun the test.
Implementar la prueba española
Let’s add the Spanish part of the scenario. Add the following valus to the end of the examples table.
Think it will all be green?
Alright, this is familiar. we need to change the es.yml file like we did the en.yml file. Open the spanish locale file.
Rerun the test. Go green!
Odd, that worked in the English version. If we fire up the rails server and go to the edit page of a location we see the name field says Name Html for both the English and Spanish locales. What happened? Let’s reflect a little… When we moved the form out of the new.html.erb file and placed it into the _form.html.erb file we didn’t reflect that change in our locale files. Let’s make that change in both locale files.
Before we test again, do you see why the English test passed? If you said it passed because “name” is in the label, you are correct. Take a bow.
Third verse, same as the first
Before we high five, remove the wip tag from the test and run cucumber to run all the tests.
In this part we dug into the source code of rails. That wasn’t so scary. We looked at log files to help figure out what’s going on. Those are full of valuable information.
Now all we have to do is delete a location and we will have a simple internationalized web application.