1. How to create vanity URLs in Rails with Devise

    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.

    Nobody shares coverlist.com/users/dani, but they can easily share coverlist.com/dani.

    I read a couple explainers — it’s fairly easy to get a descriptive URL based on the object name, there’s a gem for vanity URLs that can help you and a wonderful, albeit based on an outdated version or Rails, long description from Scribd on how to build the functionality of top-level Rails social profile 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. 

    In my user.rb:

    validates :name, :uniqueness => { :case_sensitive => false }, format: { with: /\A[a-zA-Z0-9]+\Z/, message: “No spaces or special characters, please!” }

    before_validation :downcase_name

    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.

    Also in user.rb:

    def to_param
      self.name
      name
    end

    Then, in users_controller.rb:

    def show
      # comment out # user profiles by id
      # comment out # @user = User.find(params[:id])

      # user profiles by user name
      @user = User.find_by_name!(params[:id])

      respond_to do |format|
      format.html # show.html.erb
      format.xml { render :xml => @user }
    end
    end

    Now, your coverlist.com/users/dani should be working. But you want it to be top-level.

    Go into config/routes.rb.

    Mine reads:

    devise_for :users, :controllers => { :registrations => “registrations”, :passwords => “passwords” }
    resources :users
    match ‘/:id’ => ‘users#show’, :as => :user

    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:

    , :exclusion => %w(about blog application books likes pages passwords profiles recommendations registrations users manuscripts stories jobs plans account admin signin signout signup help new popular shop tour)

    That should be it. Now you have pretty, shareable user profile URLs!

    Tags: rails / devise / vanity URLs /

     

  2. Yup, this will do.

     


  3. The real reason The Wirecutter recommends the Kindle Paperwhite

    I love The Wirecutter. First, because reading it makes me feel good about any big tech purchase — or lack of purchase. I’ve long wanted noise-canceling headphones but the reviews have helped me shy away from buying any of the ones in my budget as the quality is not that good at that level.

    So, when working on my book recommendations site, Coverlist, and deciding if I wanted to include a Buy button that would link to a site that sells ebooks, I looked to see how the various ebooks compare. I own a Kindle, am not sure what’s going on with the Nook and have heard very little about Kobo — plus, even though I don’t have an iPad, from the iPhone I know the Kindle iOS app is very good. Linking to Amazon seemed an obvious choice.

    The Wirecutter, too, makes its money with affiliate links to Amazon.com. I love this about it because that means there are no ads. So, if I decide to buy something based on a Wirecutter review, I make sure to go through the site so they benefit. 

    But even knowing this about the site, I initially found their recommendation on ebook readers to be a bit odd. They recommended the Kindle Paperwhite above all — not because of the product itself, but because of Amazon’s book library. Plus, when on every other review they offered insight on other competitive products, as runners-up, when it came to ebooks it was like they had only tested a single product. And weren’t even recommending it on the basis of the hardware itself. Which seems strange, for a personal tech site. 

    I’d been talking to a local indie bookstore about Coverlist and the manager mentioned they sold the Kobo in-store and sold Kobo ebooks on their website. It seems Kobo is putting an emphasis on creating a mutually beneficial relationship with these brick-and-mortar shops, and on selling ebooks in a format that works on other devices, whereas Amazon is mostly known for pushing bookstores out of business and building a walled garden. 

    After a bit of searching, I came across Engadget’s overwhelmingly positive Kobo review: “If you don’t mind paying for quality, do yourself a favor and take a serious look at the Aura.”

    Why, if the product is slightly more expensive but better quality, did Wirecutter not even take a look?

    Oh, because they only make money on affiliate links to Amazon. And Amazon (obviously) does not sell its competitor’s product. 

    For any other gadget, it’s not likely that there would have been this conflict of interest, but it is something The Wirecutter should have disclosed, IMO. 

    I’ve had my Kindle for over two years now, and it works well (except the Wi-Fi is broken so I have to transfer books to it by USB). Even though I don’t need a new ereader I am tempted to buy the Kobo to find out for myself if it is, truly, the best ereader.

    Tags: ereader / the wirecutter / kindle / kobo /

     


  4. How to add a Pin It button to your Rails app with a dynamic URL and description

    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: 

    <!— Please call pinit.js only once per page —>
    <script type=”text/javascript” async data-pin-hover=”true” src=”//assets.pinterest.com/js/pinit.js”></script>

    Then, all your images on your site will show a Pin It button on hover. It won’t really work on mobile, but that’s OK for now. 

    Then, make sure your alt text is filled in with dynamic information about whatever is on your Rails app. Mine was: 

    <%= link_to image_tag(@book.cover_url), “http://openlibrary.org”, alt: @book.title + ” - ” + @book.description %>

    But the Pin It button and the Pinterest bookmarklet were not finding the alt text and instead using the file name for a description. 

    Then I discovered that when you have a linked image and the image info is inside parentheses, you need to include the alt inside those same parentheses. 

    <%= link_to image_tag(@book.cover_url, :alt => @book.title + ” - ” + @book.description), “http://openlibrary.org” %>

    Now, Coverlist images can be pinned with good descriptions — of course, anyone can change it, but at least they have something to start with. 

    Tags: rails / pinterest / pin it button / ruby / programming /

     


  5. How to add fields to an existing Rails model

    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). 

    The way we do this is with a migration:

    rails g migration AddDetailsToUsers fullname:string twitter_handle:string bio:text website:string

    A “string” refers to shorter text such as a username or email, while “text” is for longer text, like a summary, or in this case, a bio.

    I ran that, and then I added  <%= f.input :bio %> to the “edit user” view to test it out — and got an error. Do I need to run rake db:migrate?

    Yes.

    Then I added a bio, and got another error: Can’t mass-assign attributes.

    I needed to go to my user model and add bio to the attr_accessible line where the other attributes are listed. The same will go for all the attributes i just added.

    One last thing — a bio is no good unless other people can see it!

    I went to the user show view and added the @user.bio in a <p> tag right under the user name. I will have to jump into the CSS later to make it look nice, but just wanted to prove I could put it there. 

    So, that was fun!

    Tags: rails / programming / learn programming / ruby / model /

     

  6. Out taking pictures like I’m a tourist! Miss this place #nofilter

    Tags: nofilter /

     


  7. it is the notion that some people feel emotions in a more physical way than others
    — meg fee - glad to know I’m not the only one who cries on the subway!
     


  8. How To Pull Book Covers From the Open Library API Into Your Rails App

    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!

    Tags: coverlist / rails / ruby / api / learn programming / airpair /

     


  9. Because regardless of whom else is interested, I want to be with me, and I always will.
    — 

    Getting Rejected Will Turn You Into a Better Dater, by Christina Bryza.

    Literally the only important thing to learn about being single, or possible about being a human being at all.

    (via luckypaperstars)

    We launched Christina’s picture book for grown-ups, Are You My Boyfriend?, last night and it was amazing. We have a handful of signed copies in the store, come by and nab one!

    (via housingworksbookstore)

    such a lovely quote!

    (Source: meredithhaggerty, via housingworksbookstore)

    Tags: dating / books /

     


  10. How Building an MVP Is About Discovery

    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?

    image

    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.

    image

    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. 

    Tags: open library / api / rails / mvp /