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

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s