From 37342a37fd1031e1ec9fc0ba87ad00aca1fa0f3e Mon Sep 17 00:00:00 2001 From: Nikita Vasilevsky Date: Wed, 23 Aug 2023 18:22:26 +0000 Subject: [PATCH] Allow redefining `to_param` delimiter using `param_delimiter` This commit allows customizing the delimiter used by `to_param` when `to_key` returns multiple value. This unblocks supporting more varieties of composite primary key types in Active Record. --- activemodel/CHANGELOG.md | 4 ++++ activemodel/lib/active_model/conversion.rb | 10 +++++++++- activemodel/test/cases/conversion_test.rb | 21 +++++++++++++++++++++ 3 files changed, 34 insertions(+), 1 deletion(-) diff --git a/activemodel/CHANGELOG.md b/activemodel/CHANGELOG.md index 4cabd1bd5c9f4..bd697f8dee7f3 100644 --- a/activemodel/CHANGELOG.md +++ b/activemodel/CHANGELOG.md @@ -1,3 +1,7 @@ +* Add `ActiveModel::Conversion.param_delimiter` to configure delimiter being used in `to_param` + + *Nikita Vasilevsky* + * `undefine_attribute_methods` undefines alias attribute methods along with attribute methods. *Nikita Vasilevsky* diff --git a/activemodel/lib/active_model/conversion.rb b/activemodel/lib/active_model/conversion.rb index 5f82039cd6e7d..90ca23897b359 100644 --- a/activemodel/lib/active_model/conversion.rb +++ b/activemodel/lib/active_model/conversion.rb @@ -24,6 +24,14 @@ module ActiveModel module Conversion extend ActiveSupport::Concern + included do + ## + # :singleton-method: + # + # Accepts a string that will be used as a delimiter of object's key values in the `to_param` method. + class_attribute :param_delimiter, instance_reader: false, default: "-" + end + # If your object is already designed to implement all of the \Active \Model # you can use the default :to_model implementation, which simply # returns +self+. @@ -80,7 +88,7 @@ def to_key # person = Person.new(1) # person.to_param # => "1" def to_param - (persisted? && key = to_key) ? key.join("-") : nil + (persisted? && key = to_key) ? key.join(self.class.param_delimiter) : nil end # Returns a +string+ identifying the path associated with the object. diff --git a/activemodel/test/cases/conversion_test.rb b/activemodel/test/cases/conversion_test.rb index 48103119fdc32..d94f6b1185e55 100644 --- a/activemodel/test/cases/conversion_test.rb +++ b/activemodel/test/cases/conversion_test.rb @@ -53,4 +53,25 @@ def persisted? test "to_partial_path handles namespaced models" do assert_equal "helicopter/comanches/comanche", Helicopter::Comanche.new.to_partial_path end + + test "#to_param_delimiter allows redefining the delimiter used in #to_param" do + old_delimiter = Contact.param_delimiter + Contact.param_delimiter = "_" + assert_equal("abc_xyz", Contact.new(id: ["abc", "xyz"]).to_param) + ensure + Contact.param_delimiter = old_delimiter + end + + test "#to_param_delimiter is defined per class" do + old_contact_delimiter = Contact.param_delimiter + custom_contract = Class.new(Contact) + + Contact.param_delimiter = "_" + custom_contract.param_delimiter = ";" + + assert_equal("abc_xyz", Contact.new(id: ["abc", "xyz"]).to_param) + assert_equal("abc;xyz", custom_contract.new(id: ["abc", "xyz"]).to_param) + ensure + Contact.param_delimiter = old_contact_delimiter + end end