Padawan coder

Getting from zero to hero...

My Top 4 Rails Tricks in My First Rails App

| Comments

Make it work, make it right, …

We began learning Rails last week at the Flatiron School, with lectures and a couple of guided Rails labs / tutorials.

In this post, I will outline the key development stages* of my first ever non-guided , albeit simple, Rails app (a ToDoList app) and my top tricks & workarounds for the current version of the app.

TL;DR:
Top 4 tricks: f.select ; f.hidden_field, to_param, button_to

The Full Monty…

As I’m sure most fledgling coders will sympathise with, it seems to be that the biggest hurdle when trying to programme an app (with limited or no guidance) is the ‘coder’s block’. The coder’s version of going tharn at the sight of a blank text-editor. What seemed doable (not to say easy) enough in a guided tutorial, suddenly seems impossible – where do I begin? what do I do?

After several weeks of countless panic attacks as part of my course, I am slowly beginning to learn to deal with my coder’s block, through the following mantras:
1) breathe… Keep Calm and Carry On
2) Make It Work, Make It Right, Make It Fast

On the second mantra, my key takeaway was that even great programmers recognise that Rome wasn’t build in a day, so for me, for now, I just need to Make It Work, by any means necessary. Even if I have use brute force** to machete my way through, the first step is to get it working.

.v001
Making it work:
With that in mind, the first major iteration of my ToDoList app was minimalistic to the extreme***. My only aims were:
1) To create lists and show them on the home page
2) To add tasks to lists

Key issues / next steps:
1) The unordered list was clearly a bad idea – users would have to guess and/or remember the number of the list they want to add their task to
2) The lists should be ordered and should be displayed on the ‘Add tasks’ page

.v002
Making it right:
Top Trick #1 – f.select
When discussing the lab in class, I mentioned that I was intending to add radio buttons to the Task new.html.erb page so users can choose the list to add their task to. Avi suggested using a drop-down menu instead, and showed briefly walked through the f.select option in the Rails form_for helper

Thus, with a short line of code, I significantly improved my user experience and interface:

new.html.erb
1
<%= f.select :list_id, List.all.collect { |l| [l.name, l.id]} %>

Making it work:
1) Users should be able to add tasks to a specific list when on that list page
Top Trick #2 – f.hidden_field
My initial intention was to have an “Add task to this list” link which would redirect to a new route along the lines of /lists/:id/tasks/new.

However, despite my valiant efforts at throwing all sorts of different code permutations and combinations at Rails, the standard new_task_path could not seem to register the fact that it had just been routed from a specific list id, and store that list id.****

As a workaround, I decided to implement a task form on the list show page (show.html.erb) with f.hidden_field(:list_id), a technique that I learnt in Jumpstart Lab’s blogger tutorial that we were assigned.

And having implemented that, I’ve realised that it works really well, and is more optimal than having to click on a link to an alternate path. Because in this case, each time the user adds a new task to a list, the list page reloads, automatically allowing the user to add another new task to the list.

3) Users should be able to delete and edit lists. As an initial testing step, I implemented the ability for users to:
i) delete the entire list only
ii) update list name and existing task descriptions

Key issues / next steps:
1) Change the routes of list from id (list/:id) to name (list/:name), to make the routes look more elegant
2) Flesh out edit list functionality – users should be able to delete individual tasks in a specific list

.v003
Making it right:
1) Added list routing via permalink (where permalink = name.downcase.gsub(“ “,”-“)
Top Trick #3 – to_param
Avi mentioned in class that you could edit the url routing by editing the to_param method in the relevant model.

I must’ve missed out the second part of his words, because I implemented that, then proceeded to struggle as Rails spat out variants of the following error as I diced and spliced my code creatively to try to get it working:

After extensive googling, I found my solution at Railscasts.

I initially used the first method, implementing "#{id}-#{permalink}" in to_param and retaining the .find(params[:id]) in the Controller. But the id of the lists would show up in the url which would not correspond to their position based on the number of existing lists (because deleted lists would retain their unique primary_key id), which I found particularly inelegant.

And so I opted for the second method instead:

list.rb
1
2
3
def to_param
  permalink
end
lists_controller.rb
1
2
3
def edit
    @list = List.find_by_permalink(params[:id])
end

Making it work:
Added functionality to allow users to delete individual tasks in a specific list, even if the ‘Delete this task’ link was very ugly and incongruous next to the compact ‘Update Task’ submit button.

Key issues / next steps:
1) Change the styling of ‘Delete this task’
2) Improve overall styling

.v004
Making it right:
1) Overall styling improved

2) Button generated for ‘Delete Task’
Top Trick #3 – button_to
Before I discovered the delightful button_to option via googling, I thought the only way to generate buttons in rails was to create a f.submit within the form_for helper. And so I tried various ways to implement a method: :delete and routing to task_path(t) within the f.submit.

Eventually, I gave up banging my head on the f.submit wall and tried a different tack - CSS buttons! But I found CSS buttons very unwieldy and impossible to style to match the ‘Update Task’ button.

button_to was a life-saver. With one line of elegant code, I managed to generate a lovely Rails-format button:
<%= button_to 'Delete Task', task_path(t), method: :delete %>

Conclusion / Next steps:
Even though my ToDoList app is still very basic for now, it has come a long way from the start, as this post has demonstrated. In fact, if I had tried to tackle even all of the basic functionality and UI in the current version of the app, I wouldn’t have dared to begin the project.

Instead, I put on my blinkers and took one baby step at a time. As my classmate Jane so aptly puts it: “How Do You Eat an Elephant? One Bite at a Time.”

So far, I have only been iterating through the process of making it work and making it right, as I’m not yet at the stage where I have the skills (or the project complexity) to make it fast.

Next steps:
1) Change the navigation links so that they are conditional – e.g. links to Home don’t show up when a user is already on the home page
2) Add authorisation for Users to create, edit and delete lists

Note: Github’s rollback has been invaluable in the creation of this post, namely the commands: git reset –-hard <commit sha id> & git push -f

* In reality, there were a lot of mini-steps / stages. But in the interest of simplicity, and because I didn’t commit often enough to be able to rollback commits to each mini stage, I am grouping the changes into 4 stages
** The phrase “brute force” is attributable to my classmate Rahul
*** With bare bones styling, because the white background and default serif fonts give me a headache
**** I spoke to Bob about this on Monday, and he told me that this would needed to be done via nested routes, a topic which will covered in future

Comments