Adding Twitter Bootstrap to Rails (part 2)

When i last left off, i was stuck with an unideal solution for displaying form validation errors — a very important part of collecting user input on the Web. Furthermore, this unideal solution broke the form layout itself. Rather than start hacking into the source code of Rails, i decided to search the Web for other souls that wanted to “add twitter bootstrap to ruby on rails” …

This led to a discovery of the following article: Twitter Bootstrap and Rails, which proved to be an invaluable source to my edification. The key ingredient was the concept of 3rd party form builders — gems that replace the default Rails form builder. The author of the article recommended SimpleForm and Formtastic, but neither seemed to solve my problem.

My issue now is two-fold: 1) produce well-formed form validation errors and 2) deploy Twitter Bootstrap assets into my web app.

Looking at solutions for Problem #2 first, i found a number of gems that purport to be a solution:

And there are even more. And yes, we are going to go over each one. You see, the one common feature i have observed from the number of blogs that discuss combining Bootstrap with Rails don’t seem to discuss Problem #1.

To be continued …

Adding Twitter Bootstrap to Rails (part 1)

Man i love me some Twitter Bootstrap. It’s the bomb. I don’t care if you convert or not. It’s mine. Thhhhpppppppttttt!!!! Jog off …

Still here? Awesome! 😀

If you’ve been reading along so far (i’m obviously talking to myself now …) you know that i have been implementing the Depot example from Agile Web Development with Rails (4th ed.) and i have been very excited about Ruby on Rails in general. But i ran into a snag when trying to replace the author’s stylesheet declarations with the ones used by Twitter Bootstrap. The author selected class names based from the default Rails form helpers — the default Rails form helpers DO NOT conform to Bootstrap. I realize now that there are better form builder gems “on the market” but i did not realize such initially, as most newbies wouldn’t. 😉

But rather than jumping ahead, why not share the journey of discovery? So here goes:

I wrapped up Chapter 7 and decided to backtrack to the beginning of the chapter and go about jabronying Twitter Bootstrap (TB) into the mix. The first step was to download the requisite TB files and move them into the respective directories inside app/assets/ and then modify app/views/layouts/application.html.erb to include them … only to discover that the existing code would automatically include the TB files for me:

The files, however, are listed in the generated output in alphabetical order which will break TB components that require jQuery but since i wasn’t using any components that required jQuery (yet …) i would deal with that … later … (Such issues sometimes resolve themselves with enough time.)

The next step was emptying all lines from app/assets/stylesheets/scaffolds.css.scss so that any generated class and id names would no longer work. Then i went back to app/views/layouts/application.html.erb and modified it to wrap a nice two-column fluid layout around the call to <tt>yield()</tt>:

Piece of cake! Now my pages were wrapped in a column and i have a placeholder for adding a left-side vertical menu later.

The next step was to modify the generated form and validation errors. I was able to modify app/views/products/_form.html.erb and easily change the existing <div> class names to those that would work with TB, but changing the <form> class name proved to be a bit more tricky:

but nothing out of the question. From here, getting the rest of the ERB tags to emit definitions and values for the class, id, for and placeholder attributes used by TB was straightforward and dare i say intuitive. Firstly, it was very easy to wrap the error summary into a dismissible error alert message:

And with some digging around in various online documentation and forum Q&A search hits i was able to emit the proper things to produce a nicely aligned horizontal form:

But it all came crashing down once i tested the validation error display. The problem was something else was wrapping a <div> tag around both the offending form element label and input control and was controlling the class name which needed to be changed. After digging around i found what seemed to be the best solution, but i was not convinced. The solution was to add the following line to config/application.rb:

This does mostly work but now we have presentation logic mixed into the configuration of the view action handler. There has to be a better way, and there is! But first, why doesn’t that solution completely work for me? Well, the reason is because even though i now have my desired class name, the handler wraps <div> blocks around the label and the input … and that breaks the horizontal alignment of the offending controls. (See image.)

Sure, you may not mind it but the $Client is surely going to sooner or later. Plus, the placement of the solution itself is totally unideal. What if there was a way to build in TB support like with a magical gem or something … turns out there is …

to be continued …

First RoR Project

I went ahead and uploaded my first RoR project to github:

This project is simply the example web app from Agile Development With Rails (4th ed.). I am sticking very closely with the instructions but i am using Twitter Bootstrap instead of the author’s stylesheets. I am also using Travis CI so i am getting some experience with basic deployment issues:

I have a few issues to solve before i should move on, such as obtaining fine control over which stylesheets and javascripts are included and which order they are included in; discovering a proper way to call rake db:migrate – right now i am using a hack:

This works and even though bundle install will be implicitly called (again), the build process is aware this instruction has already been run and does repeat the instruction. But it’s a hack. There is a proper solution … :)

Comparing Rails to Catalyst

I recall (Central Park in fall …) man i digress. I recall attempting to learn Catalyst many years ago and being hit with a lot of arcane rules and well … just plain bizarre usage of Perl in general. I didn’t like Mason nor Krang very much either but i managed to learn them. Catalyst just seemed … nasty.

Well, now i really feel like i was correct. Catalyst sucks. And so does Class::DBI for that matter. Ruby on Rails and ActiveRecord blow each counterpart out of the water, respectively.

These commands, with no need to edit any code, produced a full MVC driven CRUD interface for a fictitious “products” database (SQLite):

So far i am sold on Ruby/Ruby on Rails …

Moving onto Ruby?

Looks like I am finally making the switch away from Perl. I starting learning Ruby yesterday and so far it is everything i wanted from Perl 6, which has yet to see the light of development day. I am also enjoying Ruby far more than Python, a language i still somewhat despise.

The following quote from the 2nd Edition of Ruby Programming by Dave Thomas illustrates why i prefer Ruby over Python:

… Ruby is a transparent language. When you write a Ruby program, you concentrate on getting the job done, not on building scaffolding to support the language itself.

And the following quote from “To Ruby From Perl” illustrates why i feel comfortable switching from Perl to Ruby (rather than waiting one second longer for Perl 6)

Although $ and @ are used as the first character in variable names sometimes, rather than indicating type, they indicate scope …

But the latter quote warrants further discussion: Ruby is not afraid to use sigils like Perl (Python) but it is also not afraid to challenge the fundamental design choices that i feel really matter as opposed to ones that otherwise serve egos (Perl6). I am not saying the Perl6 community did not make fundamental changes, they did. I am saying they made the wrong changes/choices.

Speaking of which, what you just read are all my personal choices/opinions. And as such i don’t have to defend them. But i do want to announce that from this day forward i am serious about Ruby.