A fully fledged Ruby on Rails CRUD application encompassing some staple Ruby Gems.
Welcome to Samipedia, an application that allows users to create public and private Markdown-based wikis.
This is not supposed to be a finished product but was part of the learning process of my web development course with Bloc covering core programming topics.
To create this application as a sole developer, working remotely, completing specific tasks outlined by Bloc.
It was time to delve further into the world of backend development. Become more familiar with servers, databases, MVC1, routes and HTTP requests. And overall develop a far more holistic understanding of web applications.
Given my desire get to the bottom of things and understand the inner workings, I found this rather enjoyable, being able to trace and direct a users request all the way from the frontend through to the backend and back out to the frontend again.
I was provided with User Stories 2 that I had to comprehend and complete.
- As a user, I want to sign up for a free account by providing a user name, password and email
- As a user, I want to sign in and out of samipedia
- As a user with a standard account, I want to create, read, update, and delete public wikis
- As a developer, I want to offer three user roles: admin, standard, or premium
- As a developer, I want to seed the development database automatically with users and wikis
- As a user, I want to upgrade my account from a free to a paid plan
- As a premium user, I want to create private wikis
- As a user, I want to edit wikis using Markdown syntax
- As a premium user, I want to add and remove collaborators for my private wikis
I derived from these user stories some wireframes for my design of the frontend.
On top of the above I was expected to implement TDD3 using RSpec.
I used Git to maintain a local repository of the project and a remote repository on GitHub, and used feature branches to ensure a smooth workflow and secure version control.
Lastly, I decided to deploy my application on Heroku using their CLI, to further enhance my knowledge of Hosting, DNS and Domain Names.
Building an application of this nature from scratch meant there were numerous tasks and problems that needed to be solved. Given the limited scope of this work I will attempt to name a few to give you an insight into the generic challenges faced and my approach to them.
- Create three different roles a user can have, standard, premium and admin.
- Use Stripe to charge users before switching their account role from standard to premium.
_formpartial that contains the form for new/edit action. Then render this partial in new and edit views. Too much logic to handle one checkbox. Move the logic to helpers or models.
- This would prove to be tricky. Each user would have different permissions depending on their role, so it was important to be able to track a current users role and cater permissions to actions within the controller accordingly.
The relatively easy part would be to establish a users role and persist that information to the database.
I had already created a user model so it just required me to add another column in the model which would hold the details of a users role.
Two important things I did here, was save the
role attribute as an
enum, this provides some handy methods which could be used when on the
current user object to determine the users role. Moreover, I set the role to be standard by default unless instructed otherwise.
I had now created roles for each user and thanks to the Devise Gem I had some great helper methods (
current_user) that would allow me in the views (with my
enum methods) to determine what role my user occupied.
This just left me with the task of setting up the permissions.
Now technically, I could have simply hidden forms or buttons on the frontend but this would not be as secure as setting permissions on the backend.
In order to achieve this I used a gem called pundit to set up policies for my wiki resource.
Great! This worked so all was good to go! (or so I thought…)
Cue a well-needed code review:
good start but please fix following:
Try to optimize code in policies. I noticed that generally, your conditionals are much more complex then they should be.
After implementing this your code will look much better.
Bloc Grading Team
I knew it myself. My logic had become far too complex, difficult for me to comprehend, let alone anyone else and this type of code was too susceptible to bugs as my application scaled up.
Time to refactor:
Great, three different user roles, which carry different permissions throughout the application.
2. I decided that as well as allowing users to upgrade their account from standard to premium.
I also wanted users to be have the option to sign up for a premium account initially. This meant editing Devise’s built-in sign up view.
Additionally I needed to edit Devise’s
registrations controller, so I could redirect a user who opted to sign up for a premium account to the
new charge view, where I could take a payment through Stripe before changing the role on their account to premium.
Now, I could redirect the User to the
new charge view and allow my
charges controller to handle the Stripe payment and upgrade the users account accordingly.
The code in the charges controller to facilitate the Stripe payment:
(I used a Ruby Gem called Figaro to keep any sensitive information such as
Awesome job. I like how you’ve used tooltips and the dropdown menu. Everything works great including your signup for premium and pay right away.
Seems like if you don’t pay it still allows you to see the title of the Private wikis but once you click into one it won’t let you see it and tells you that you need to upgrade.
I like that as its a way to get people to upgrade.
Bloc Grading Team
3. At this stage I had reached the end of the project and I had the site up and running with no bugs detected. However, my views were not as slim as they should be. Moreover, they contained too much logic, I needed a way to tidy this all up.
The main areas of concern were the
edit views for wikis:
By moving the form to a partial I was able to slim down both these views significantly
Lastly, in order to handle the logic surrounding the checkbox on the form, I created another partial for the checkbox itself, which was called from inside the form partial, this kept the form partial slim:
I then slimmed down the logic for the checkbox in the checkbox partial:
Note: These were not necessarily the hardest problems or challenges faced when building this application, for more complex functionality please feel free to look over the source code on Git Hub. However, the idea is that you can get a feel for some of the problems and my systematic approach to them.
My main form of testing for my rails application was using RSpec(150+ tests). This helped me to catch any bugs far quicker and meant I didn’t need to be overly concerned when refactoring my code or changing other features in the application. I also tested things using
rails console and Byebug, which proved invaluable.
I was able to achieve the desired outcomes of the course project and more importantly I was really able to further my understanding of Ruby on Rails and all the accompanying technologies, RVM, RSpec, servers, HTTP Requests, Ruby Gems, Params etc…
Feedback from my codementor was positive.
I was really being challenged with this project to use my own initiative and external resources right from the get go. There was minimal guidance from Bloc as this was the second project I was undertaking using Ruby on Rails. Consequently, I was apprehensive about my own ability to achieve the desired outcomes.
However, in some respects this allowed me to learn and grow the most. I began to access the wider rails community, forums, stack overflow, ruby gems, documentation. With every successful feature or code snippet my confidence began to grow and this helped me to become more creative and pursue my own ideas of how I felt the code should function and the project should look. This was empowering but also more enjoyable for me as I felt I could take ownership of the project.
The biggest and most valuable learning curve whilst undertaking this project, was by far the power of refactoring. Initially, I was slightly perturbed by the code review that I had to undertake (even though I knew it must be done). I had got to a stage where my code felt disorganised and like an unstable lego tower, it was currently upright but I didn’t want to touch anything at the risk of something breaking. However, what I learnt was that after a good nights sleep, you can achieve so much by going over your code, trying to slim it down, reassessing the logic, and as a result of this, my code would develop less bugs, be scalable and easier for other developers to reason with.
Going forward, this experience of refactoring code that initially I didn’t want to touch, will give me confidence in the future to refactor and reap the rewards. Furthermore, when writing code initially, I intend to be more aware of the potential disorganisation that can occur as the code base increases, and try keep my code more organised and structured so I dont run into problems when the application grows at a later stage.
1: The Model-View-Controller (MVC) is an architectural pattern that separates an application into three main logical components: the model, the view, and the controller. Each of these components are built to handle specific development aspects of an application.↩
2: A user story is a tool used in Agile software development to capture a description of a software feature from an end-user perspective. The user story describes the type of user, what they want and why. A user story helps to create a simplified description of a requirement.↩