-
-
Save pietromoro/6cfbd500b8cec4b79e1383f6ebccba32 to your computer and use it in GitHub Desktop.
module Sluggable | |
extend ActiveSupport::Concern | |
cattr_reader :slugging | |
included do | |
before_save :generate_slug | |
def self.sluggable | |
all.extending(Sluggable::Finder) | |
end | |
def self.slugging attribute | |
@@slugging = attribute.to_sym | |
end | |
end | |
def to_param? | |
return nil unless persisted? | |
slug | |
end | |
module Finder | |
def find(*args) | |
id = args.first | |
return super if args.count != 1 | |
resource = resource_by_slug(id) | |
resource ||= super | |
raise ActiveRecord::RecordNotFound unless resource | |
resource | |
end | |
private | |
def resource_by_slug(id) | |
find_by(slug: id) | |
end | |
end | |
private | |
def generate_slug | |
return unless send("#{slugging}_changed?".to_sym) | |
self.slug = send(slugging).parameterize | |
end | |
end |
Awesome, thanks!
Awesome!!!
I ran into some issues implementing this. The @@slugging is a class variable shared throughout the classes that includes the Slug concern. This becomes an issue if I want to use the concern on more than one class, for example:
class Person < ApplicationRecord
include Sluggable
slugging :name
...
end
class Company < ApplicationRecord
include Sluggable
slugging :alias
end
When rails loads my classes, the slugging
method sets the @@slugging == :name at first and then sets @@slugging == :alias, making it only work when I am dealing with Company objects. If I want to update the slug of a Person, I get a undefined method 'alias_changed?'
error for a Person.
I think that the best approach would be defining the class variable for each class using the concern with an cattr_accessor
.
Hey! yes, you are right, I came across the same problem long time ago and always forgot to fix it in this gist. Did it now! Thanks for the heads up!
Usage
Add slug:string column to your model (e.g. Post)
$ rails g migration AddSlugToPost slug:string
Then in your model class
And in your controller do