diff --git a/app/models/topic.rb b/app/models/topic.rb index c3ac40ae016..db73eee2ac2 100644 --- a/app/models/topic.rb +++ b/app/models/topic.rb @@ -1191,11 +1191,26 @@ class Topic < ActiveRecord::Base } end + cattr_accessor :slug_computed_callbacks + self.slug_computed_callbacks = [] + + def slug_for_topic(title) + return '' unless title.present? + slug = Slug.for(title) + + # this is a hook for plugins that need to modify the generated slug + self.class.slug_computed_callbacks.each do |callback| + slug = callback.call(self, slug, title) + end + + slug + end + # Even if the slug column in the database is null, topic.slug will return something: def slug unless slug = read_attribute(:slug) return '' unless title.present? - slug = Slug.for(title) + slug = slug_for_topic(title) if new_record? write_attribute(:slug, slug) else @@ -1216,7 +1231,7 @@ class Topic < ActiveRecord::Base end def title=(t) - slug = Slug.for(t.to_s) + slug = slug_for_topic(t.to_s) write_attribute(:slug, slug) write_attribute(:fancy_title, nil) write_attribute(:title, t) diff --git a/spec/models/topic_spec.rb b/spec/models/topic_spec.rb index 37590f3c4c0..b708bf93553 100644 --- a/spec/models/topic_spec.rb +++ b/spec/models/topic_spec.rb @@ -270,6 +270,37 @@ describe Topic do end end end + + context 'slug computed hooks' do + before do + invert_slug = ->(topic, slug, title) { slug.reverse } + Topic.slug_computed_callbacks << invert_slug + end + + let!(:title) { "hello test topic" } + let!(:slug) { "hello-test-topic".reverse } + let!(:other_title) { "other title" } + let!(:other_slug) { "other-title".reverse } + let!(:topic) { Fabricate.build(:topic, title: title) } + + it "returns a reversed slug for a title" do + expect(topic.title).to eq(title) + expect(topic.slug).to eq(slug) + end + + it "returns a reversed slug after the title is changed" do + expect(topic.title).to eq(title) + expect(topic.slug).to eq(slug) + + topic.title = other_title + expect(topic.title).to eq(other_title) + expect(topic.slug).to eq(other_slug) + end + + after do + Topic.slug_computed_callbacks.clear + end + end end context "updating a title to be shorter" do