rails

Right now I’m working with a team of developers on the ReadThisNext mobile app – they are working in Swift, and I am building the Rails API. That means every week or so they send a new build, and ask me to fix things that are broken with the API. Recently they ask why the “Create Post” action was not working.

After some sleuthing, the error messages were telling me that Create Post was triggering Create Book which was triggering Soulmate (the plugin that adds books to search results). The problem is, when you create a post with a book_id included, this should not happen. Create Post should only create a book if book_id is missing.

This was all through the curl command, which I use to test the endpoints I send to developers.

I went to check the same action through the web interface. Oddly enough, it was still hitting Soulmate, because it gave me an error unless Redis (works with Soulmate) was running.

I tried removing the command that would add a new book if book_id was empty and still got an error in curl saying book_id was empty because the validation is set to prevent a post from being created without a book. On the web, I could add a post with the correct book successfully.

It seemed like curl wasn’t recognizing that I had included the book_id. I tried changing the validations to after_create or after_validation, just in case the Rails validations were only seeing text in a text box and not in the curl command for some reason. That didn’t work.

I tried searching for this problem and came up with nothing. My general rule with programming is that, if you have a problem, it’s likely that someone else has had it before. When I can’t find it with a simple Google search, something is fishy.

Because it was working on web, I knew it had to be something to do with the curl command, so I asked a question on Stack Overflow. The first comment was: “’twould be helpful to include the controller code that you hit with that POST.” I wish people on Stack Overflow didn’t have to sound like such dicks when they ask obvious questions.

But, as I went to find the Create Post code which he was referring to, I decided to include another bit that tells Rails which attributes it is allowed to update. I thought I had checked this before, but I hadn’t – because book_id was missing. I must have checked the code for web, which is on a different page.

After 1+ hours of working on this solo, it saved me a ton of time to post it on Stack Overflow, even if someone else didn’t technically answer my question. Otherwise I might have given up and removed a feature, or tried to build around it, when the answer was really very simple!

It’s always excited to hear someone say they quit their job to work on their own thing, whether it’s a startup, or a music career, or something else. But I’ll admit, there are times when I’ve wondered — really? But … food? Rent?

Who ARE these people who can just quit working and work on something that doesn’t pay, and might not pay, at least for awhile. It would be easy to assume that these are special people who have rich parents, still helping them out well into their 20s. In New York, people who once worked in finance seem to be able to pull off not working and without income for awhile.

I got laid off from a job once and made it maybe 2.5 months thanks to a little freelance work, but it wasn’t like I had a buffer — I had to get moving asap.

So when I decided to start a company, I was baffled as to how I might pull this off. To make matters worse, I had steep student loans — to put it into perspective, my loan payment matched my rent each month.

What I’ve found is that there IS no “how to” on this topic because every person does it differently. Each person has their own situation, but if you want to start a company, you figure yours out.

Without the support of a significant other, or rich parents, or a high-paying job that nets you lots of savings, and even with student loans, it IS possible to start a company that you’ll eventually work on it full time.

Here’s mine, plus a few other ideas mixed in.

1. Work your company into your day job

I wanted to start a startup that would somehow gamify the process of selecting the best book manuscripts, then edit them and market them to readers. I’ve worked for a literary agent and gotten paid to edit a full-length manuscript that was self-published. I could have started a service company and gotten paid per project — then scaled it and turned it into the platform I envisioned.

But, I decided that wasn’t the best entry point into the type of business I wanted to run.

2. Lots of savings

A friend recently quit her job with a years’ worth of savings (she also lives with her significant other). She also has student loans.

My personal opinion is that you should have at least six months savings before quitting a job. Any less and you’re giving yourself unneeded stress and that won’t help your company.

A year is good — but I took the opposite route, and while I have nearly no savings (I DO have an emergency fund), my student loans are almost paid off, which reduces my monthly expenses, for when I do finally quit my job.

3. Move to Thailand

I read about a guy who moved to Thailand to bootstrap his startup. I haven’t been to Thailand and would love an excuse, but this goes back to the savings question — although you could get further on less savings, or you could do remote freelance jobs, as long as the time to payment ratio still gave you enough time to work on your own stuff.

4. Move home with parents

I’ll be honest — I didn’t ever really consider this. I lived with my parents right after grad school. They are wonderful, but retired, and very leisurely, and arrange their days around morning coffee, mid-morning coffee, and afternoon coffee. I love going home and resting, but I wouldn’t get any work done.

There’s also something to be said for surrounding yourselves with a community of likeminded people who will drive and inspire you to get sh*t done.

5. Work nights and weekends

This is, of course, what I did. I worked at Mashable for two years while teaching myself programming and eventually building ReadThisNext on the side. I’ve worked at a startup and I’ve worked at a coffee shop, and neither of those was conducive to building something creative on the side. At the startup, I poured my heart into the day job, and at the coffee shop, I was literally just too exhausted to do anything after work, and had no extra money, so I had to make up for it by cooking at home consistently, which takes up time and effort.

The salaried job that I enjoyed was ideal. I actually found the days I was more creative and proactive at work, I came home energized and excited to do more work on my own stuff. There was no upside to being lazy at work. A couple times I actually turned research I was doing on my own (about fundraising, about startup accelerators) into stories I wrote for Mashable, so everyone benefitted.

When I came to Bustle, I not only had just moved into a cheaper apartment but the raise meant I could finally afford to invest some of my own money into my company. I could potentially start paying a developer to build features faster than I could myself (having to teach myself as I went). I felt like Westley and Buttercup when they came out of the Fire Swamp and had defeated the various dangers — Hey, I could do this happily for some time!

(and therein lies the problem. When you start a company, comfort is the enemy.)

6. Do freelance or part time work

I’m going to be starting Monday with a team of journalists at Facebook. The role involves working some nights and weekends, and flexible hours, so I’ll have some daytimes free to do meetings for my company. It’s a really great job. If you told Grad School Me that I would get this job, I wouldn’t have believed you — back then I wasn’t sure I’d get any job in journalism. Much less have THAT job, and my own functioning and beautiful startup MVP, and freelance writing clients.

My cofounder also has a steady job and we’re both able to commit a healthy number of hours each week to ReadThisNext WITH confidence that we don’t need investment asap or revenue asap. I am quite happy with the setup, and for us to take our time finding the right business model and the right user experience.

When you work on a startup, I think you have to have a sense for timing. You think raising money would be a huge success — but all that does is give you an end date, a big red deadline. Who needs that kind of pressure? Get product-market fit first. Then get revenue first. Weigh your risks, and take the best ones.

You might have followed this lovely tutorial to add the even lovelier SearchKick gem to your Rails app: https://shellycloud.com/blog/2013/10/adding-search-and-autocomplete-to-a-rails-app-with-elasticsearch

But, if you’re like me, you got a little stuck when deploying to Heroku.

First, SearchKick is a gem that uses Elasticsearch and you did start by installing Elasticsearch. Bonsai’s first tier is free, so it’s a good option if you’re already using Heroku. But, when you follow the Bonsai setup instructions on Heroku, you might be confused as to why you need to add the elasticsearch-rails gem, the elasticsearch-model gem, and the bonsai-elasticsearch-rails gem to your app. You don’t need these! You have SearchKick, which has Elasticsearch in it.

Coverlist originally was built to be a place where readers could recommend books, but along the way it veered into being a place for authors to showcase their books and also showcase the blurbs other authors were writing about their books. These authors would need to be able to easily promote their own profile page, and one of the most important features I would need to add to the app would be vanity URLs.

It turns out, the process was easier than the information I found had let on.

First, if you’re building user profiles with /username, or top-level URLs, each user needs to have an attribute that is unique and lowercase and without punctuation. I’m using Devise and users sign in with their email and password, but they also are required to make a “name” which must be unique.

If someone registers with “Dani,” I don’t want someone to come and register with “dani,” because browsers will read it as the same.

After that, you want Rails to serve the User show view when it sees coverlist.com/dani. Right now it’s responding to coverlist.com/user/25. First, you need it to look for your “name” attribute, not the user ID.

The order is important because the routes.rb file reads things in order. So, if you have a controller that matches a user’s name (as I have a controller called books, so coverlist.com/books will list all books), Rails knows to show the controller action, not the user profile.

That said, you don’t want users to register with a name that you do or plan to create a controller with. To prevent that, you can add this line, in user.rb, to the end of your validates name, listing any possible conflicts:

Every week, I see several people discover Coverlist via Pinterest, and it’s always from the same pin – the one of book Eleanor and Park.

I want to encourage people to Pin beautiful books from Coverlist, but because the book descriptions (micro-reviews, if you will) are both short and unique, I wanted those to be represented on Pinterest as well.

But the Pin It button was just pulling the image file name, which I could not control, because I am pulling images from Open Library’s API.

I found out that 1. Pinterest uses alt text for automatic descriptions, and 2. I had implemented alt text wrong on my book images.

First you need to add the following code to your application.html.erb page:

In Coverlist, I have a model (scaffold?) called Users, which has a small number of components: name, email, password, all created when a user makes an account.

But, in order to expand the feature set of the site, I’d like for users to be able to add a short bio, a website, their Twitter handle and their full name (since name actually refers to username, and their vanity url, ie: coverlist.com/users/Dani).

My goal was to display covers via Open Library rather than forcing users to upload a cover from their desktop. The API makes it easy to pull covers by ISBN, but I don’t store that and don’t want to force users to look it up, so we decided to let users put in a title, which would then be run in a search on Open Library.

Ideally, Open Library would return 8-10 book covers and the user would select the correct one, but this would require a bit of Javascript for the interaction. Instead, to get the API up and running, we just had Coverlist use the first cover in the search results (if there are no results, it will pull nothing and the cover will be blank).

Yes, this is a temporary solution.

We also used HTTParty to parse the API.

– Add HTTParty to Gemfile

– Add a few lines of code to Create action in controller – make a variable for search results, then parse, then assign new variable for cover_url that refers to the Open Library book ID url where the cover is stored (they prefer you link back to them rather than downloading and saving their covers).

– Run a migration – had to add cover_url to books (ended up doing it manually)

– Change views to show cover_url instead of cover

Here is the full experience in Google+ Hangout

After we finished this lesson, the solution worked locally but not on heroku.

I forgot to do heroku run rake db:migrate and heroku restart. Then it worked.

Then I needed to do an If/Else statement so users could override the Open Library cover with their own cover, in case the app pulled the wrong one. If there is a manually uploaded cover, that is shown – if not, the cover_url cover is shown.

Right now it only interacts with the API on create, not update (although this could be easy to change) so if you put in Harry Potter for title, it might be a toss-up which book of the series you get. Thus, a few improvements should be made to this API integration, but the exciting part is that Coverlist is using its first API. And it happened in one hour. Much easier than I expected. Bigger things to come!

I was building the MVP of Coverlist and I was nearly done. Users could add books they had read along with a 2-3 line microreview, which would serve as a recommendation for other users who are just browsing – and every book had a Coverlist score so I could surface the best books for the weekly top 20.

It was time to do things that don’t scale – i.e., start reading out individually to people in book clubs or people blogging about books. But I was scared – what if, they went to add a book, realized you had to find the cover image on your own to upload the file, and decided it was too much of a hassle?

The app was mimimal, but was it viable? Or would they walk away and never return?

I started with my sister – “sign up for this site I built, add a book and tell me what you think.”

She added Emma and as hoped, she picked a unique book cover via Google Images that perhaps would not be available in an API. I want users to be able to pick book covers and not be stuck with whatever the publisher wants to promote, since Coverlist is a visual place.

The downside was that she picked a cover image that was smaller than the rest, and could throw off the design.

My mom was next. She added a book cover that was even smaller so I had to replace it. Turns out she had found it on Amazon, and then offered to take it down so I wouldn’t have a “pirated image” on the site.

As it turns out, users did not have a problem with uploading images – but opted for images that might disrupt the site design, and possibly felt they were breaking a copyright by pulling images from other sites (which is up for debate).

I don’t want users to feel uncomfortable about adding a book and I definitely don’t want to worry about the design supporting all sorts of small and large cover images.

What most surprised me, though, was this book, added by someone I don’t know. Instead of adding a cover image, the user simply took a snapshot of the physical book – which is actually a great experience when you’re using Coverlist in a mobile browser.

It had never occurred to me that someone who is still reading from physical books could quickly upload their book library by simply taking photos from a smartphone. But, in order to allow Coverlist to be a collection of all your books – whether you read a borrowed copy, got it from the library, own it or read the ebook – I still would need to offer a cover database.

So I decided I would need to add an API so users could search for a book title and choose an image instead of uploading a file.

I might be returning to the same decision I pondered in the first place, but I came to it from watching user interactions rather than just making assumptions – and now I can make a better case for investing time into making the new feature happen.

If you Google “The page you were looking for doesn’t exist Rails Heroku” you’ll find the StackOverflow questions from beginning developers who expect this message has something to do with the problem they’re facing. What they don’t know is that this is just the default 404 page in Rails, which they wouldn’t have encountered until deploying to Heroku (when your app runs locally, it gives you an actual error message).

I was convinced that the text and design on this page was due to Heroku and searched all over the site trying to find out how to change it to something more user-friendly. Eventually, I realized that both the HTML and CSS was literally a file in my app’s ‘public’ folder.

If you want your error pages to look at home on your website, all you have to do is change the code in these three files – 404.html, 422.html and 500.html.

I opted for a pun relevant to my users, who are book readers. “We seem to have lost our page. Can we start from the beginning?” along with an image of book shelves I found on Imgur.

What if you had to design a logo before you could do any other work on a project? It’s funny, because I messed around in Photoshop for a day, and created something that I actually really liked. I kept it on the site for a while. But once I added a huge beautiful background image to the home page, that logo couldn’t stay. It was too cheap and the blue was too bright.

That’s why design seems never-ending for me – as soon as one feature is updated, others that were done suddenly need to be improved as well.

Plus, I’ve had a long list of changes anyway – to the point that it’s hard to walk away from my laptop to go to bed.

Goals for Last Week:

I wanted to fix the design on the home page. I also wanted to change the content flow so users would see only one book at a time, then hit one of the buttons to reach the next page – and each book would be on its own permalink page (so you can share a specific book url to social media).

I wanted to utilize a rotate feature in CSS so the book info could be on the “back” of the books.

There were a few broken features around users – you could “like” a book more than once but there was no way to remove it from your library. I also haven’t decided whether to call it Your Library or Books You’ve Read.

I got to thinking a lot about the Buy link. Right now I can put it in manually for each book if I want to use an Amazon affiliate link, or I can redirect to an Amazon search of the book title. But I was thinking about how the interaction on Coverlist is really made for mobile – it’s simple – and I wondered if I should actually be redirecting to iBooks or Google Play. I looked it up and those affiliate links are actually quite easy to implement. Of course, I would want to bring the device in use into it – the site would detect that someone was on desktop and send them to Amazon, or iPad and iBooks, etc.

I’m also thinking about allowing users to add both a short review and tags to books. That way a user doesn’t need to have multiple “shelves.” I think it would be more attractive to tag a book “sad” “2013” and “beach,” for example – that would turn into better discovery for others as well.

What I Accomplished:

I actually did a lot! Mostly today. I got the home page redesigned, with the help of a friend I met on Angellist. He sent over CSS/HTML/Javascript. It took me some time to implement it.

Coverlist has Twitter Bootstrap on it. That means there’s CSS I don’t need to repeat, but also CSS I need to override. Simply copy/pasting CSS from another project usually doesn’t work. Sometimes I do it just to see what happens, then remove it, go back and add things one by one as they make sense. I actually learned a lot from that exercise, though.

I also figured out how to get the vote buttons to scroll through books. I found a StackOverflow question about Previous and Next buttons on individual articles and used the code from the Previous button. Then I had the “Begin” button on the homepage direct to Book.last. It’s not a permanent solution, but a good hack. I have no idea how to set cookies so users don’t see the same books every time they visit – but this way if I add books every week, they should see the new ones first.

I also met up with a friend who did YC last summer. I told him a bit about the idea and it was a really helpful conversation. He actually told me to stop writing code. Startups are always asked how they know they’re building something people want. Sure, it would be great to finish making Coverlist look how I want, and then start to get users – but the business model is most likely based on working with publishers. So, I should talk to them.

There are so many ideas from building an iPad app for local bookstores to use that would allow visitors to read and purchase ebooks, giving the bookstore affiliate revenue. Or, providing services to writers who want to self-publish. Or, charging for placement in the book list. Of course, affiliate links to digital stores, or straight from the publishers themselves. But the one I think may be most compelling is A/B testing for book covers. It’s unique to the platform and could serve as a first step to offering publishers other support in digital.

Lastly, I removed access to user accounts. They are still there, but you don’t need to be logged in to see the books or vote on them. That saved me from having to fix the related bugs, redesign the Library view and more.

Oh! And I discovered a fun hack. So since the Meh, Yes. and Ooh! buttons work like a Previous button, the buttons were disappearing on the first book. I wanted to reward users and tell them they’d reached The End. I realized instead of changing the code, I could just create an image that was book cover shaped and replace the first book with it. I used Canva for that and it worked beautifully.

Goals For This Week:

Surprisingly, my endeavor to stop coding went really well. The site looks decent on mobile (well, at least on my iPhone) and works. The one thing I do need to code is that Heroku is serving a weird error page if someone were to try to navigate to a book that doesn’t exist. I think I can change this inside Heroku.

Otherwise, now I’m planning for promotion. I’ve done some blogging on coverlist already but there’s more original content I can do. I want to do some interviews with book cover designers and editors and take book quotes and put text overlays on photos with Studio (iPhone app) – right now I just need to do the prep work. I also want to put at least 100 books on Coverlist. Lastly, I found that the few books I pinned to my personal Pinterest when I was testing the Pin button actually resulted in traffic to the site – not much, but more than from Tumblr, which I was more active with. So I’ll be planning a fun Pinterest promo 🙂

One Thing I Learned:

Coding is fun. Too fun. It’s always a debate for me whether I like programming enough for that to be the primary thing that I do. But in this case, I think fear of success plays a part – I’m not spending all my time learning Rails because I want to always do it – it’s because if I start telling people about Coverlist they might reject it – or I might actually have to follow through with this crazy adventure.