To me, forms in web applications feel antiquated. There are better ways to get data from a user, such as getting access to a user’s other accounts (like Twitter or Facebook) via OAuth and populating data from there, but that’s not always an option. For now, we still have to input data manually and that means we need to use forms.
Forms are obnoxious. You have to pick out which input types are best for your scenario (text, radio buttons, dropdown lists, etc.). You need to style it with CSS so it looks presentable You need to define a route for the form to submit data to the back end. You have to deal with data validations and handle scenarios where users input unacceptable data. And you have to deal with a host of other miscellaneous issues that come with such complex interaction.
Here’s a sample HTML form:
Fortunately, Rails can help you generate forms using a few different tools which we’ll look at here.
form_tag is a Rails form helper used to help you build a basic form.
Here’s a sample form_tag form:
The actual HTML that’s produced will look like this:
Just with a few simple lines of ERB, we’re able to create a fully realized form. It has an action and method already defined, as well as an authenticity token which is used to help prevent cross-site request forgeries.
However, form_tag is limited, specifically when it comes to dealing with forms directly related to back end models. If you want a different action method (such as wanting to reuse the same form for creating and editing a model), you have to specify it manually. It also won’t populate the form with data that’s already there. That’s where form_for comes in.
form_for is like form_tag in that it helps you generate a form with ERB tags in a view template. However, form_for directly connects with a model in your Rails application and makes it easy to allow the creation of new model instances in your database.
Here’s a sample form_for form:
This creates the following HTML:
This is something that we can reuse for a create and an edit form, and it will populate data in the form automatically if there’s data there. The thing to remember here is that form_for needs an instance of the model to use which has to be provided from the controller. So for example:
Of course now we need to wire these forms up with controllers in the back end to actually process the data, but that’s a topic for another day.
My first experience with object oriented programming came with Java while I was coding in high school. I never learned Java properly, and it wasn’t until working with C++ later on that I got a better understanding of the OOP paradigm.
Here’s some sample ruby code defining a song class.
The attribute accessors define and give read/write access to instance variables - variables that are tied to each instance of the class. But in the initialize method, they’re referred to by the keyword self. self is simply a way to refer to the instance itself. So for the actual song object that is created, self.name refers to that specific song’s name.
When self is being pushed onto the @@all class array, self is being used by itself to push that whole object onto the array.
self is also used to define class methods, methods that don’t aren’t a part of instances but the class itself. For example, self.all returns the @@all class array.
The idea of self-referential objects can be tricky if you’re just starting to learn OOP, but it’s necessary in order to build objects that can access their own data.
Earlier in my education when I was coding in C++, I was using Subversion for version control (specifically TortoiseSVN). SVN worked well enough, and in class we were able to share code for the different projects we were working on effectively. But since then, for better or worse, the world has moved on to Git. You can read about the differences on countless websites, like here, so I won’t get into it.
For most of my efforts learning web development, I’ve been using Github. It’s the go-to destination for uploading, revisioning, and sharing code. A remote on Github is just a repository stored on their servers. You code locally on your machine - or your cloud IDE - and push code from your local repo to your remote. Because I’ve been coding in multiple development environments, this has made keeping code consistent relatively easy.
Earlier when I was using SVN, I didn’t create multiple branches to develop different feature sets without breaking the master, something I try to do now when using Git. I’ve come to find that both systems offer great functionality, but your own practices for managing your code will ultimately make the most difference.
Making the decision to learn a hugely difficult skillset is not something to be taken lightly. This is especially true when it requires immense technical knowledge. So deciding to make a commitment to software development, for me, was a big deal.
Previously, I had been working as an artist and designer. I loved art, but found the business side of creative work to be punishing and contrary to what made me passionate about art in the first place. As I spent years doing freelance jobs and checking job listings, the reality of the market eventually became clear. Artists were rarely in demand, but there were always openings for programmers.
Software developers create products and facillitate services in ways that directly create value for users and employers. In contrast, the work that artists and designers do will always be more limited. In order to be relevant, you need skills that can actually solve people’s problems, and art just wasn’t enough of an answer.
I had programmed before in the past - dealing with languages like Visual Basic, Java, and C++. I had enjoyed being able to create functional, interactive products, and solving problems in logical, algorithmic ways. It offered me a way to create more value for others and at a certain point, it became obvious that in order to achieve my goals, I needed to switch tracks.
Making a Rails application is hard. There are so many components, considerations, and features to be dealt with that the process can quickly become complicated and overwhelming, especially when you’re just starting out as a developer. For my first full-fledged Rails project, I’ll give an overview on how I broke down the process and attempted to build out the application one piece at a time.
The application is tentatively titled Storyplan and is intended as a tool to help writers plot out stories. Writing a story often requires a great deal of structure, planning, and constituent components, and I wanted to create a website that would make it easier to build and keep track of everything.
I started by mapping out the models and migrations. Using the rails generate resource command, you can use Rails to generate a model, database migration for that model, and a controller, and I used it to get a head start. My models were as follows:
User - Generated using the Devise gem for authentication.
Story - Belongs to a User.
Chapter - Belongs to a Story.
Character - Has many Chapters through a join table and vice versa, belongs to a User.
Audience - Has many Stories through a join table and vice versa.
Genre - Has many Stories through a join table and vice versa.
Comment - Belongs to both a User and a Story.
With these models, I was able to set up the associations necessary to do things like show all the Stories of a User or all the Characters in a Story. This also makes it easier for a user to explore the different connections of a writer’s work.
These models have a variety of validations to ensure bad data isn’t entered into the system, as well as class and instance methods to give the models additional functionality beyond being mere data containers.
The Story model:
Routes and Controllers
Unlike Sinatra, Rails has a separate router from its controllers and uses it to map the routes to actions in those controllers. My routes were mostly resources for the above mentioned models, with a few nested resources to do things like the find all the Characters of a particular User.
As far as controllers are concerned, I used one controller per model with a few miscellaneous controllers thrown in as well to handle other tasks. This is basically a CRUD (Create, Read, Update, Delete) application, so many of the controllers handle similar tasks. So for example, the Stories controller handles serving all the stories for the stories index, showing a particular story, serving a form for a new story or editing an old one, processing the creation and update of a story based on input from the form, and destroying a story as well. These correspond to RESTful routes (Representational State Transfer): Index, Show, New, Create, Edit, Update, Destroy. This is simply a paradigm to keep things consistent across different web applications and is an example of Rails’s philosophy of convention over configuration.
There are other levels of complexity involved, such as authorization (making sure the user creating or updating a story has permission to do so) or white-listing the data received (using strong parameters) from the form so no improper data is forcibly entered.
For the front end, I used the Bootstrap-Sass gem for Rails. It has a very generic look to it, but for now it works to help it look presentable.
The views use a variety of partials to make the display code reusable. For example, for each model, there is a partial that creates a sort of visual card for it that includes pertinent information. I then use a grid system to display collections of that model.
Code for the story card partial:
So when you go to the stories index page, it displays a grid of stories that simply repeat that model partial with new information from each collection item.
Setting up a secure login/logout system can be challenging considering the number of security threats out there. You can roll your own authentication using bcrypt to securely store password hashes, but I wanted something with more functionality built in. That’s why I used the Devise gem which provides for the creation of its own User model and gives you additional tools like email confirmation should you desire them. Most importantly, it’s battle tested and commonly used to provide secure authentication for Rails applications.
In addition, I used Devise to provide OAuth authentication for Facebook, so you can securely sign in with a Facebook account as well.
Overall, this is just a small overview of what turned out to be a relatively complex project. There’s a lot more functionality I’d like to build eventually to make this more of a viable tool for writers, including building more of a front end, but for now it serves its purpose.