In the previous post we looked at using AngularJS to progressively enhance a basic Rails form.
In this article we’ll expand on that to build a more complex example with dynamic fields that map one to many models, that you can add or remove inline with Angular, then we will look at handling form state for the non js ( Plain Old Post ) form’s add/remove in Rails, to give a percieved ‘inline’ effect similar to the Angular functionality.
And in the next article ( Part 3 ), we’ll look at progressively enhancing the form with inline validations in AngularJS that fall back to Rails standard validations when JS is unavailable.
If you want to see a working example of this tutorial, just download version 0.0.2 of the app ( assuming you have the capability to run Ruby on Rails on your local machine ) from the releases section of the Github repo.
We will need to add/remove fields on the client ( Browser & Angular ) and persist the form data on the server ( Rails ). So first, we will implement an active model based solution for the Rails backend.
A nested model
First, lets create our nested model for the one to many example:
And add the has many reference and mass assignment to the author model in
Now run the migrations to update our schema.
The next thing to do is set up the controller and form for our new model. Add a partial at
app/views/authors/form/_articles.html.haml with the fields:
And then include this partial in the form view.
_Now set up the respective controllers … _
app/controllers/authors_controller.rb build an instance of article in the new action:
And modify the angular code at
A model form service
Now that we have added a new set of nested fields with a nested key
author[article], the Angular code needs to be modified to handle the attribute keys in the same way that Rails would do. Otherwise we will end up with complex code or multiple end points doing virtually the same thing. To do this we wrap the form data model in a seperate service.
The service looks like this:
But for the sake of simplicity look at the diff to get a better idea, and follow on from there.
Adding and removing articles.
Now that we have a form service handling our form submission, we can start to think about adding and removing authors and how to implement these in JS and POP ( Plain Old Posts ).
We’re going to start with the progressively enhanced version and the fallback to POP with the help of some directives. Directives are a feature of Angular that enable you to do stuff.
We open up our authors partial at
app/views/authors/form/_articles.html.haml. And add the buttons that we are going to use, so that the template reads like this:
Now we add the angular directive code to enable us to swap out the old submits that we added with the nice angular links.
Handling the form with Plain Old Posts.
This part pays homage to the concepts outlined in Hexagonal Rails.
In order to add and remove articles without the use of angular or ajax, we will need to use some plain old posting with form state handling added in to give us an almost up to par user experience.
The plot thickens …
To notify the server that we are adding or removing articles we need to send back a parameter with the submission so that the server app can render the correct response. First, lets modify our enhanced submit buttons by adding an index and some name attributes that will get sent back to the server when the button is clicked.
The new view after we have made some more modifications.
Now that we are telling the server what we pressed when we submit the form, we can write a form handler to process the submission accordingly. Lets add some hexagonal magic to facilitate this.
First, create the form handler in
app/handlers/authors_handler.rb, something like this should suffice for now:
Will will use this handler in the create action of our authors controller, which is the action that our form posts back to every time we press a button in the form. Based on the parameters that are sent back to the server, we can deduce whether or not the request is a form “state_change” or an actual attempt to save the data. First we refactor the create action so that it reads as follows:
And now we add some callback methods to our controller subscriber clas, these will perform the correct response actions based on the outcome from the form handler.
Also, don’t forget to add the articles attributes to the controller’s
permit attributes, you’ll need to change the author_params method like so:
Now we have a working create form that will submit new data to the server both asyncronously ( the progressive bit ) and traditionally the Plain Old Post bit.
see the full source code changes here » If I have left anything out in this post, please leave a comment and I will update it accordingly.
In the next article, we will look at progressively adding validations.