Previously, I’ve written not only about processing markdown in a different way but using the Carrierwave gem as a way to add some pictures to my blog. However, until today (article started on July 12, 2016), I haven’t worked on integrating them into the blog proper. Of course, if you look at the list of articles, I have been working on other projects, and learning new things, so even though I’ve played with them separately, they are not currently part of the ‘live’ app. (That’s the stuff you guys read for non-programmers who up until now are my primary audience - in fact as of this date my primary audience is people related to me in one way or another)
I’ve already implemented Kramdown, with tests of course, in my development version of the blog, but i haven’t set up Carrierwave yet, nor have I taken advantage of Kramdown’s ability to add classes, nor the ability of the combination of bootstrap and sass to easily extend and override existing classes to improve the layout of my articles. For instance, I don’t really like how blockquotes are defaulted in markdown so I’m going to change that for sure.
So, here’s the plan for this blog and the next few articles.
- Integrate Carrierwave (with tests) into the development environment of this blog.
- Improve the layout in various ways, especially changing how blockquotes are displayed.
- Upload all the changes to this live app, which, perhaps, seems trivial, but the move to Kramdown from Redcarpet will require some editing of all previous articles, plus now that I’ll have image uploading, I’ll want to use that as well on older articles where it might seem appropriate.
Let’s get started shall we.
Previously I have written about my exploration of the two more well known image (and file in general) uploading gems, Carrierwave and Paperclip. I detailed how I had always assumed that Paperclip would be my upload gem of choice, but after working with both of them, I found that Carrierwave was more suited to my style and would be the upload gem for this blog, but that was about a month ago compared to this (initial) writing and I haven’t integrated it fully yet, but there is a good reason for that, well a couple reasons.
First off, other projects pressed into my mind, existing and new ones that drew me away from working on bettering this blog. Secondly, it’s not as simple as installing the gem. Not only do I need to test, I need to make sure that I install it properly to hide it from unwanted eyes (all of yours for now). This requires not only setting up the uploading but hiding it behind my admin namespace, and all the testing involved in that as well. It’s not a herculean task by any means, it’s just not something I was ready to do until now (and I wasn’t ready to upload the Kramdown version of the blog and tweak all the articles, but alas, that has to happen at some point I guess since since I put it on the master branch and not its own branch. Silly John.).
So, let’s get to it; writing tests and installing Carrierwave in my app.
The first step in adding any functionality, as always, is writing the tests first. Rails in Action 4 does use Carrierwave (which is one of the reasons I was motivated to try it), which allowed me to get some ides on how to properly test the successfully installation of this gem. I’m not attaching it to a ticket the way the book does, but I can use the tests they write as guidance in writing my own. The basic first test will test only if my picture uploads properly. This involves creating the proper routes/controller/model that I’m going to use for my pictures. Which is a step-by-step process that the tests push you into following properly.
- You tell your test to go to a specific page, but that page doesn’t exist yet, so you have to modify your namespaced admin route to include pictures (all options for now)
- Your path works but then your test fails cause, well, the controller you referenced in your routes (1) doesn’t exist yet, and that’s a problem, so, create your controller.
- Whoops, now the
newaction can’t be found to go to the page you tell your test exists to upload the photo.
Now, after 3, I could continue this backwards path of defining
new, then having the view option fail, then having the form fail because the instance variable is nil, but that seems a bit much, plus I feel like I’ve been over it enough that I can just go ahead with model creation, and gem installation which really should happen now, so it does. Well the Carrierwave github repository lays claim to a version 1.0 coming at some point, the most recent version I find on rubygems.com is 0.11.0 so I slide that into my gem file, and bundle it up. Of course, adding the gem doesn’t really do anything, it just makes it so that I can use Carrierwave once I have the set up to use it.
The first step I take is to create the model (Picture) that I’m going to use as my repository for any picture information I may need (independent of Carrierwave) in the future. For now it’ll be a simple name field for the file, so I can assign it a name to reference the picture myself. A quick
bin/rails g model Picture name:string, followed by a simple
bin/rake db:migrate and we have our Model set up to build some basics to progress on the testing path. Immediately, I realize I’ve made a mistake. The database represented by the Picture model also needs a string field to represent the uploaded file to Carrierwave (which I would have known if I had ‘measured twice cut once’). Thus, I have to do a second migration to add that attribute as well. Same principle as above, but just a different field name. Since this field will ‘locate’ my picture, I called it locator.
Then I started building my form, like one does when one needs user input, but I forgot how you have to deal with a namespaced controller within a form. Thus the basic
ruby failed because I hadn’t referenced the admin controller, which you have to do or Rails won’t build the path properly. That’s not Rails fault, it’s mine, so I initialize my form properly with `` and my test proceeds properly to the fail point where Carrierwave is required to move on. I followed the basic steps of including attached pictures to a record via an uploader, and ran my test, which should pass pretty easily. However, sadly, my test didn’t pass, it failed. The error message referred to an undefined method
picture_url' for #. My intuition said, ok, this is a namespace issue, so I went to StackOverflow and did a quick search on namespace Carrierwave, and since I got returned questions, my problem should have been solved, but, alas, it wasn’t.
It turns out that other people have had a similar (if not exact) issue/error while using Carrierwave within a namespace, but no one ever seemed to have provided a workable answer that I could find. Next I did something I hadn’t done before. I went to the gem issue history to see if namespace had ever come up. While there was a merged issue regarding namespaces, that didn’t seem to solve my problem either. So now I was back to square one with Carrierwave and since I foolishly hadn’t worked on a branch I had to manually undo what I presumed was going to work (as the Richard Marx song Should’ve known better ), so I had to start over, but this time silly John, use a branch.
Thus, a branch was created, and I replicated all the work I did previously but without the namespacing and the tests successfully passed to allow uploading a photo. Now that the function wasn’t hidden behind my admin wall, I had to tweak the tests to test for non-admin users being properly shunted away from the photo uploading and the admin user still being a allowed in to the functionality itself. This did lead to some repeated code as the
check_authorization method I use to make sure no one can get into things but me was resident in the base controller for the admin namespace. However, now that I had to put the Carrierwave functionality outside that namespace, I had to duplicate the method within the application controller to make the new tests pass. However, with the power of inheritance and the way the namespace base controller was set up (to inherit from the application controller) i was able to change the code so that the
check_authorization method exists in only one place and can still be called when needed. For those who don’t know, this is done by removing the duplicated instance of the method (commenting it out so it still exists if you need it) and running all your tests again. If your tests all pass (as mine did), you’ve shown that while you removed the duplicated method definition, the functionality still exists everywhere you need it to. (This, though small, is the true power to me of testing and why you really should build them all, even the basics, all the time.)
And that next part sounds pretty awesome, but I can’t get there just yet. My tests for creating/uploading new photos is incomplete. I must test for and implement validation that requires a name be entered and a file be attached to successfully upload a photo.
The first part of this is completing the ‘new picture’ portion of the testing, which I proceed to do by writing tests for (and then creating the proper functionalities for) requiring not only an image name and an image itself, but also restricting file types and limiting the maximum file size allowed for an uploaded image. This isn’t too important with just me having access, but it makes sense as a functionality within a blog if you want to allow other users access to file uploading in the future. File size limitations are not built in to either Carrierwave or Ruby on Rails, but as with most things, there is a gem (that the Carrierwave docs pointed me to) called file_validators that adds the ability to validate the size of an uploaded file as easily as you can validate the minimum/maximum length of a user data entry.
Testing the display of all pictures had a few kinks primarily in understanding the capybara method
have_link, but it also led to pretty cool build in rails helper that I hadn’t heard of called
in_groups_of. For my less informed readers, I will try and explain. Whenever click on a page on a web site that presents some sort of list of items, it most likely pulled those items from the database and assembled them into a grouping, so that they could be accessed by the application and all the relevant information displayed. More often than not you will see information displayed as one single column. This isn’t so much a design choice usually, as it’s how the default display is done, i.e. it requires the least amount of code to give you all the information. The application accesses each member of the group of results you requested, displays them, and then moves on to the next one, treating it as ‘one row at a time’. I don’t fully like that and it’s often a waste of screen space, which I find silly. After some StackOverflow research, I happened upon said
in_groups_of which allows the Rails programmer to take ‘sub-groups’ from that large grouping and treat it as ‘one element’ of the group before going on to the next one. This allows you to access the entire ‘sub group’ on one row before going to the next one. It’s a nice little display trick that might come in handy in the future as other projects get more complicated, and present larger amounts of information.
So, that’s it for Step 1 in the upgrade. Carrierwave is integrated and tested. A quick final GACP to the github repository (only) and it’s on to step 2.