26

I'm using the following:

gem 'friendly_id', github: 'FriendlyId/friendly_id', branch: 'master'

I am creating an Article section on my Rails 4 website. The problem I am having is that when I change a existing article's name the slug is not updated.

This is what I have so far:

extend FriendlyId
friendly_id :name, use: :slugged

add_column :articles, :slug, :string
add_index :articles, :slug, unique: true
Brian
  • 5,951
  • 14
  • 53
  • 77

3 Answers3

61

In FriendlyId 4 (Rails 3 compatible) there was a method

should_generate_new_friendly_id?

and you could define it on your model to control when slug is regenerated. Try

def should_generate_new_friendly_id?
  name_changed?
end

to regenerate slug when name changes.

EDIT

FriendlyId version 5 (Rails 4 compatible) doesn't regenerate slugs on save anymore. To restore this functionality you can either set slug column to nil before saving or use the solution provided above.

EDIT 2

You need to override the slug setter for your saves to work for Rails <5 & FriendlyId > 5 as referenced in this issue.

Add this to the model file

  def slug=(value)
    if value.present?
      write_attribute(:slug, value)
    end
  end
Community
  • 1
  • 1
Mike Szyndel
  • 10,461
  • 10
  • 47
  • 63
  • was name_changed? an random example? or should we add '_changed?' for the model? – Harsha M V Jun 27 '14 at 14:57
  • 8
    @HarshaMV `[attribute]_changed?` is a method generated for you by Rails. – Mike Szyndel Jun 28 '14 at 11:33
  • 1
    pfff honestly, even setting the slug to nil is not working. Since friendly_id has updated for rails 3, version 5 etc… it just got randomly working. Meaning, *mega-randomly*. Too bad. – Ben Oct 23 '14 at 12:02
  • @Ben Can you elaborate? Maybe by asking new SO question, I'm eager to help you resolve it. – Mike Szyndel Oct 23 '14 at 16:41
  • Yup I did explained a little bit more here : http://stackoverflow.com/questions/26533422/rails4-remote-links-and-templates-naming thanks for the help you'd provide – Ben Oct 23 '14 at 17:02
  • Best workaround I've found is to manually set the slug to nil, and re-save the model every time you do anything that requires it be updated. We cannot count on "dirty" (changed?) working (per above), and there is not a way I know of to move the gem's callback later in the callback-cycle (i.e. not in before_validate). – JosephK Dec 17 '19 at 06:59
6

I have this issues and just want to point out what I've noticed.

if you only do as in docs

class Post < ActiveRecord::Base
 extend FriendlyId
 friendly_id :title, use: :slugged
end

and then run Post.find_each(&:save) - slug is gonna get updated...

However in my case, I also have these in my model

class Post < ActiveRecord::Base
 extend FriendlyId
 friendly_id :title, use: :slugged

 def normalize_friendly_id(text)
   text.to_slug.normalize(transliterations: :russian).to_s
 end

 def should_generate_new_friendly_id?
   title_changed?
 end
end

with the code above it won't do anything when you run Post.find_each(&:save) I assume since your title doesn't change. (first method handles russian language)

so when working with the first model all worked great, but then when I copied ready code to next model I wanted to slugify, I run into some issues. Hope it helps someone.

AndreiMotinga
  • 1,024
  • 17
  • 24
  • I'm not sure what your comment is trying to illustrate - it's clear the second code example with the two method definitions is problematic, but in what way was it problematic? How did you resolve the issues? Which version of Friendly_Id and Rails are you running? Thanks :) – kfrz Apr 18 '18 at 14:28
  • 2
    It's been 2 years, but I'll try to answer :). I believe the point was that sometimes you want custom behavior in terms of whether to update title or not. suppose you 1. added `should_generate_new_friendly_id?` 2. some time passed and now you want to regenerate slugs again. `Post.find_each(&:save)` - as suggested in docs isn't going to work. I guess it was the point. – AndreiMotinga Apr 19 '18 at 15:10
1

I was facing a similar issue where the slug don't want to change on update even though I had the following in my model:

def should_generate_new_friendly_id?
  slug.blank? || title_changed?
end

In my case I wasn't setting the title directly via the form but in a before_save callback, and that was the reason, because it seems that FriendlyID needs the change to happen not only before saving but even before_validation so I changed my code to:

before_validation :set_title

def set_title
  self.title = 'some dynamic way of getting title'
end

And, that worked for me!

I really spent too much time trying to figure out why it wasn't working, so I'm posting this case here for anyone who may get stuck in the same situation (and hopefully save you long hours of debugging)

medBouzid
  • 7,484
  • 10
  • 56
  • 86