Removing User_ID from url params with Devise and FriendlyId gem

We have all our user profiles rendering through a handlebars template but as the attributes associated to the user grows, so does the loading time.

The only reason we have them loading through a handlebars template as opposed to a ruby template, is that the user_id is in the URL for devise/show.

Here is a quick guide to replicate how I solved that:

Installation

Gemfile:

gem 'friendly_id', '~> 5.1.0'

Terminal:

rails generate friendly_id

 

I already have Devise set up for user authentication, so next I ran

rails g migration AddSlugToUser slug:string:uniq

Which produced this migration file:

class AddSlugToUser < ActiveRecord::Migration[5.0]
 def change
   add_column :users, :slug, :string
   add_index :users, :slug, unique: true
 end
end

 

Mmmmkay – let’s migrate those goodies

rake db:migrate

 

Implementation

I want the URL to use the first_name of the user. Many members might have the same first name, so I’m going to give the function a few options. The first option is to use just the first name. If that is taken, append a random number 1-10. If that is taken, append a random number 1-100, and then 1-1000.

user.rb

class User < ApplicationRecord

  extend FriendlyId
  friendly_id :slug_candidates, use: :slugged

  def slug_candidates
    [
      :first_name,
      [:first_name, rand(1..10)],
      [:first_name, rand(1..100)],
      [:first_name, rand(1..1000)]
    ]
  end

end

 

Now I ran in the console:

User.find_each(&:save)

And I can see each user now has an attribute called slug, and it is their first_name, plus a unique number (or just first_name for the early birds!)

 

Adapt current setup

Currently, I have a profile controller, where each user can view their own profile

routes.rb

 get 'profile/:id', to: 'profile#view', as: 'view'

So, for the signed in user to view their profile, I changed the link to:

link_to main_app.view_path(current_user.slug)

 

Now, to render another user’s profile, running through an array of User records:

link_to image_tag(user.avatar.url(:medium)), main_app.view_path(user.slug)

 

 

 

 

Since I’m not requiring users to have a unique first_name, this will occasionally end up in a REALLY ugly url, such as:

walsh-0243024c-3c43-4526-87a3-0327654626bb

because there are sooo many Walshs in the world.

 

The next step is to put the ability for a user to chose their own unique URL identifier, and save it in their settings. This will cut down on the chance that a unique name+number will be taken, when creating new users. I might write another blog post about this in the future, but for now it’s pretty straight forward in Friendly_id’s documentation

 

One interesting ‘gotcha’ I discovered later:

 

Started GET "/profile/queue" for ::1 at 2017-04-13 11:05:57 -0500

  Processing by ProfileController#view as HTML

  Parameters: {"id"=>"queue"}

Completed 401 Unauthorized in 1ms (ActiveRecord: 0.0ms)

 

Here, there was a route to a page called profile/queue. But now that the view is not profile/:id in a numeric, ActiveRecord id sense, it is looking for a slug called ‘queue’

 

Simple fix:

get 'profile/queue', to: 'profile#queue', as: 'queue'

to

get 'queue', to: 'profile#queue', as: 'queue'

 

 

PS. My roommate has a goldfish name Friendly, which is why the image for this post is a goldfish 🙂

 

Advertisements

Lexody wins at SXSW!

Lexody was invited to pitch at SXSW’s Pitch Accelerator.

After 2 rounds, and 30 incredibly qualified companies, Lexody was ultimately crowned the Best One-Minute Pitch!

No, Keith McKellar and I, did not plan coordinating outfits that day… but must have know we would be taking pictures holding a giant check.

Watch the winning pitch:

Thank you for all your support! We are both really excited about the future, and know this is the first of many accomplishments for Lexody!

 

-Walsh Costigan, Founder

Make a Rails5 API that spits out JSON

This post is for me. Specifically to work with another app, which takes an api, and spits out a random question from another API.

create new rails app

rails new app_name --api

 

Create a table

rails g scaffold table_name attribute:type

 

We want a random question to be returned. In the Questions Controller, index method:

@questions = Question.order("RANDOM()").limit(1)

 

In order to allow the api to be accessed by a different app/url, add in application.rb:

 

config.action_dispatch.default_headers.merge!({
 'Access-Control-Allow-Origin' => '*',
 'Access-Control-Request-Method' => '*'
 })

 

Because I’m deploying with Heroku, which uses PostgresSQL (Not sqlite) in Gemfile, remove

gem 'sqlite3'

and replace with

group :development, :test do
 gem 'sqlite3'
 gem 'rspec-rails', '3.0.1'
end

group :production do
 gem 'pg'
 gem 'rails_12factor'
end

 

Create new git repo on github, and follow directions on pushing

Deploy to Heroku

heroku create, push, rake db, seed, open, et voila!