-
-
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
endWhen 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:stringThen in your model class
And in your controller do