diff --git a/lib/grape/jsonapi/entity/resource_identifier.rb b/lib/grape/jsonapi/entity/resource_identifier.rb index ca48671..ad318cc 100644 --- a/lib/grape/jsonapi/entity/resource_identifier.rb +++ b/lib/grape/jsonapi/entity/resource_identifier.rb @@ -8,11 +8,28 @@ class << self attr_reader :type_plural end + def self.inherited(subclass) + class << subclass + attr_accessor :custom_id_proc + end + super(subclass) + end + def self.root(plural, singular = nil, for_real = false) @type_plural = plural super(plural, singular) if for_real end + def self.entity_id(attribute_name=nil, &block) + self.custom_id_proc = if attribute_name != nil + ->(capture) { capture.send(attribute_name.to_sym) } + elsif block_given? + block + else + raise ArgumentError.new('must provide an attribute name or a block') + end + end + expose :id, format_with: :to_string expose :json_api_type, as: :type @@ -24,6 +41,10 @@ def self.root(plural, singular = nil, for_real = false) private + def id + self.class.custom_id_proc.is_a?(Proc) ? self.class.custom_id_proc.call(object) : object.id + end + # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity def json_api_type diff --git a/spec/grape/jsonapi/entity/resource_identifier_spec.rb b/spec/grape/jsonapi/entity/resource_identifier_spec.rb index 56556db..0717d6c 100644 --- a/spec/grape/jsonapi/entity/resource_identifier_spec.rb +++ b/spec/grape/jsonapi/entity/resource_identifier_spec.rb @@ -93,4 +93,50 @@ def json_api_type end end end + + context '#custom_id_proc' do + subject do + fresh_class.represent(data).serializable_hash + end + + let(:record_id) { 'ID' } + let(:alternate_id_attribute) { 'ALT_ID_A' } + let(:alternate_id_block) { 'ALT_ID_B' } + let(:data) do + OpenStruct.new( + id: record_id, + other_attribute: alternate_id_attribute, + ) + end + + context 'when custom id is specified' do + let(:fresh_class) { Cow } + + context 'as an attribute name' do + before { fresh_class.entity_id :other_attribute } + + it 'uses the custom id' do + expect(subject[:id]).to eq alternate_id_attribute + end + end + + context 'as a block' do + before { fresh_class.entity_id { |obj| alternate_id_block } } + + it 'uses the custom id' do + expect(subject[:id]).to eq alternate_id_block + end + end + + end + + context 'when custom id is not specified' do + let(:fresh_class) { Mouse } + + it 'uses the record id' do + expect(subject[:id]).to eq record_id + end + end + + end end