Skip to content

Override for relationship with super is not working. Also setter for a relationship is working anomalously #405

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Open
isfando opened this issue Jan 13, 2023 · 2 comments

Comments

@isfando
Copy link

isfando commented Jan 13, 2023

class BillingAccount < JsonApiClient::Resource

#internal class starts
  class Create < JsonApiClient::Resource

    property :billing_account_type, type: :string
    has_many :products, class_name: 'foo'

    def product_offerings=(items)
      #item._model is of type 'foo'
      self.products = items.map { |item| item._model }
    end

    def attributes_for_serialization
      relationship_keys = self.class.associations.collect(&:attr_name).map(&:to_s)
      super.reject { |k, v| v.nil? || relationship_keys.include?(k) }
    end

    def self.key_formatter
      JsonApiClient::UnderscoredKeyFormatter
    end

    def self.path(*)
      Bssapi::V1::BillingAccount.path
    end

    def meta
      {
        channel: 'abc'
      }
    end


    def as_json_api
      super.tap do |data|
        data['type'] = BillingAccount.type.dasherize
      end
    end

    def save(sync: true)
      saved = super()
      if saved && async_response?(last_result_set) && sync
        when_async_request_done(last_result_set) do |request|
          if request.done?
            self.id = billing_account_id
            true
          elsif request.failed?
            errors.add(:base, request.reasons || "unknown error")
            false
          end
        end
      else
        saved
      end
    end
  end
# internal class ends here


  has_many :products, class_name: 'foo'
  has_one :billing_account_type, class_name: 'bar'

  def meta
    {
      channel: 'abc'
    }
  end

  def product_offerings=(items)
    #item._model is of type 'foo'
    self.products = items.map { |item| item._model } 
  end

  def valid?
    if new_record?
      create = resource_for_create
      if create.valid?
        true
      else
        errors.merge!(create.errors)
        false
      end
    else
      super
    end
  end

  def save(sync: true)
    if new_record?
      create = resource_for_create
      if create.save(sync: sync)
        self.id = create.id
        true
      else
        errors.merge!(create.errors)
        false
      end
    else
      super()
    end
  end

  private

  def resource_for_create
    Create.new(
      attributes.merge(
        billing_account_type: billing_account_type # This is a relationship in GET and string in POST
      )
    )
  end
end

###########################################################################################################################
###########################################################################################################################
Reason for internal class:
Use a different class for POST to avail asynchronus creation etc.

Problem during Creation of new resource:
BillingAccount.new(
billing_account_type: "test",
product_offerings: items,
).save

The products relation will be absent from resulting pay load to api.

POST http://localhost:7777/api/v1/billing-accounts with body 
'{"data":{"type":"billing-accounts","attributes":{"billing_account_type":"1111"}},"meta":{"channel":"abc"}}'

If i remove the method #product_offerings= from the outer class (BillingAccount) then it works fine

POST http://localhost:7777/api/v1/billing-accounts with body 
'{"data":{"type":"billing-accounts","relationships":{"products":{"data":[{"type":"foo","id":"33333"}]}},"attributes":{"billing_account_type":"6002"}},"meta":{"channel":"abc"}}'

The method in the outer class BillingAccount is required for PATCH as BillingAccount::Create is only used for POST.
What can i do in such situation.

I have also used the following method to override the products relationship in BillingAccount::Create but it does not help either

class Create < JsonApiClient::Resource
  property :billing_account_type, type: :string
  has_many :products, class_name: 'foo'
  
  def products=(items)
    #item._model is of type 'foo'
    super(items.map { |item| item._model }) 
  end
end
@isfando
Copy link
Author

isfando commented Jan 13, 2023

@sebasjimenez10 i read one of your posts and that helped somehow with POST and using super in relationship override method. But it does not work with PATCH

#390

@sebasjimenez10
Copy link
Contributor

@isfando to clarify, when you tried doing BillingAccount.new.tap do |...| it still didn't serialize the object as expected?

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants