Tag: seo url

ActiveRecord and FriendlyId: slug not generated when field set with before_validation callback

FriendlyId is an awesome gem for slugging and permalinking for Active Record. It works like a charm except one case: when you set friendly_id field in a before_validation callback.

Here's an example:

class User < ActiveRecord::Base
  extend FriendlyId

  friendly_id :login, use: %i( history finders )

  before_validation :set_login

  def set_login
    # This weird method will just generate a random string
    self.login = (0...8).map { (65 + rand(26)).chr }.join
  end
end

User.new.save!
User.last.login #=> 'bhkcjvrd'
User.last.to_param #=> user id
User.last.slug #=> ''

It happens because FriendlyId uses a before_validation callback to set a slug. This method is invoked before any before_validation callbacks that you define in your class.

To fix this you can either invoke friendly_id after you set your before_validation callbacks, or you can just prepend your method before friendly_id:

class User < ActiveRecord::Base
  extend FriendlyId

  friendly_id :login, use: %i( history finders )

  before_validation :set_login
    prepend: true

  def set_login
    # This weird method will just generate a random string
    self.login = (0...8).map { (65 + rand(26)).chr }.join
  end
end

User.new.save!
User.last.login #=> 'bhkcjvrd'
User.last.to_param #=> 'bhkcjvrd'
User.last.slug #=> 'bhkcjvrd'

FriendlyId Ruby on Rails gem – update (refresh) slug after each record change

If you want to have slugs that are refreshed (updated) each time you change corresponding field in your ActiveRecord models, put this at the end of your initializers/friendly_id.rb file:

module FriendlyId
  module Slugged
    def should_generate_new_friendly_id?
      return true if send(friendly_id_config.slug_column).nil? && !send(friendly_id_config.base).nil?

      change = :"#{friendly_id_config.base}_changed?"
      return true if respond_to?(change) && send(change)

      false
    end
  end
end

This will update slug each time related column (friendly_id_config.base) has changed. Keep in mind, that this method won't work if you use non-column slug method as a base for friendly ids, since it uses ActiveRecord::Dirty interface.

Copyright © 2024 Closer to Code

Theme by Anders NorenUp ↑