Skip to content

Commit

Permalink
Set slug to previous value on validation failure
Browse files Browse the repository at this point in the history
On create, set slug to nil if unrelated validations fail.

On save, set slug to previous value if unrelated validations fail.

Without this change, Rails forms will sometimes use a new, unpersisted
slug value as the form action URL, and submitting the form will result
in a 404.

Resolves #642
  • Loading branch information
norman committed Jun 1, 2015
1 parent 5abe8da commit 1f8af74
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 1 deletion.
11 changes: 10 additions & 1 deletion lib/friendly_id/slugged.rb
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ def self.down
class Person < ActiveRecord::Base
extend FriendlyId
friendly_id :name_and_location, use: :slugged
def name_and_location
"#{name} from #{location}"
end
Expand Down Expand Up @@ -248,6 +248,7 @@ def self.included(model_class)
defaults[:sequence_separator] ||= '-'
end
model_class.before_validation :set_slug
model_class.after_validation :unset_slug_if_invalid
end

# Process the given value to make it suitable for use as a slug.
Expand Down Expand Up @@ -324,6 +325,14 @@ def slug_generator
end
private :slug_generator

def unset_slug_if_invalid
if errors.present? && attribute_changed?(friendly_id_config.query_field)
diff = changes[friendly_id_config.query_field]
self.slug = diff.first
end
end
private :unset_slug_if_invalid

# This module adds the `:slug_column`, and `:sequence_separator`, and
# `:slug_generator_class` configuration options to
# {FriendlyId::Configuration FriendlyId::Configuration}.
Expand Down
41 changes: 41 additions & 0 deletions test/slugged_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,47 @@ def should_generate_new_friendly_id?
end
end

test "should not set slug on create if unrelated validations fail" do
klass = Class.new model_class do
validates_presence_of :active
friendly_id :name, :use => :slugged

def self.name
"Journalist"
end
end

transaction do
instance = klass.new :name => 'foo'
refute instance.save
refute instance.valid?
assert_nil instance.slug
end
end

test "should not update slug on save if unrelated validations fail" do
klass = Class.new model_class do
validates_presence_of :active
friendly_id :name, :use => :slugged

def self.name
"Journalist"
end
end

transaction do
instance = klass.new :name => 'foo', :active => true
assert instance.save
assert instance.valid?
instance.name = 'foobar'
instance.slug = nil
instance.active = nil
refute instance.save
refute instance.valid?
assert_equal 'foo', instance.slug
end
end

end

class SlugGeneratorTest < TestCaseClass
Expand Down

0 comments on commit 1f8af74

Please sign in to comment.