My app assigns slugs in the usual way using the friendly_id gem:
class Organization < ApplicationRecord
extend FriendlyId
friendly_id :name, use: :slugged
strip_attributes
end
When a user changes the organization.name, by default the slug does not change. But I want to give the user the option to reset the slug to match the name.
From the console, this is simple:
>> organization.update(slug: nil)
Friendly_id jumps in with a before_validate hook and generates a new slug. But if I try setting slug
to nil
using the OrganizationsController#update method, it doesn't work:
Started PATCH "/organizations/slo-mo-100?organization%5Bslug%5D=" for 127.0.0.1 at 2017-10-10 16:37:30 -0600
Processing by OrganizationsController#update as HTML
Parameters: {"organization"=>{"slug"=>""}, "id"=>"slo-mo-100"}
Organization Load (0.5ms) SELECT "organizations".* FROM "organizations" WHERE "organizations"."slug" = $1 ORDER BY "organizations"."id" ASC LIMIT $2 [["slug", "slo-mo-100"], ["LIMIT", 1]]
(0.3ms) BEGIN
SQL (4.1ms) UPDATE "organizations" SET "slug" = $1, "updated_at" = $2 WHERE "organizations"."id" = $3 [["slug", nil], ["updated_at", "2017-10-10 22:37:30.077956"], ["id", 1]]
(0.2ms) ROLLBACK
Completed 500 Internal Server Error in 24ms (ActiveRecord: 6.2ms)
PG::NotNullViolation - ERROR: null value in column "slug" violates not-null constraint
I'd like the #update action to act just like the console does, that is, to assign a new slug when the incoming value is set to nil.
It turns out the solution is quite simple. The problem is that the update parameters come through with slug set to an empty string ({"slug"=>""}
) instead of nil
. I am using the strip_attributes
gem to convert empty strings to nil, but strip_attributes
wasn't getting called until after friendly_id
had already checked to see if the slug
field was nil
.
I solved the problem by switching the order of the callbacks to fire strip_attributes
before friendly_id
:
class Organization < ApplicationRecord
extend FriendlyId
strip_attributes
friendly_id :name, use: :slugged
end