Rails Project - Storyplan
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.
Models
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 aUser
.Chapter
- Belongs to aStory
.Character
- Has manyChapters
through a join table and vice versa, belongs to aUser
.Audience
- Has manyStories
through a join table and vice versa.Genre
- Has manyStories
through a join table and vice versa.Comment
- Belongs to both aUser
and aStory
.
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.
See the story controller here.
Views
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.
Authentication
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.
Conclusion
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.
You can find the source code for this project here on Github.