Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Reduce need to work arounds #337

Open
code-bunny opened this issue Mar 26, 2019 · 3 comments
Open

Reduce need to work arounds #337

code-bunny opened this issue Mar 26, 2019 · 3 comments
Assignees

Comments

@code-bunny
Copy link

code-bunny commented Mar 26, 2019

While perhaps better as three separate issue, they are all interconnected so I will group them into one group of bugs.

Custom endpoints don't respond to route_format changes. We have fixed this with

  JsonApiClient::Query::Requestor.class_eval do
    def custom(method_name, options, params)
      path = resource_path(params)
      params.delete(klass.primary_key)
      path = File.join(path, method_name.to_s)
      request_method = options.fetch(:request_method, :get).to_sym
      query_params, body_params = [:get, :delete].include?(request_method) ? [params, nil] : [nil, params]
      path = path.dasherize if klass.route_format == :dasherized_route
      request(request_method, path, params: query_params, body: body_params)
    end
  end

Has one associations has a bug from the latest code change, fixed by applying .underscore

  JsonApiClient::Associations::HasOne::Association.class_eval do
    def load_records(data)
      record_class = JsonApiClient::Utils.compute_type(klass, data["type"].underscore.classify)
      record_class.load id: data["id"]
    end
  end

And finally relationship_data_for was falling apart when there was no key? method on the relationship_definition which is triggered by assigning and array to a has_many relation which is fixed by making more if's as I am not too sure of all the inner workings

  JsonApiClient::Resource.class_eval do
    def relationship_data_for(name, relationship_definition)
      # look in included data
      if relationship_definition.try(:key?, "data")
        if relationships.attribute_changed?(name)
          return relation_objects_for(name, relationship_definition)
        else
          return included_data_for(name, relationship_definition)
        end
      else
        if relationships.attribute_changed?(name)
          return relationship_definition.to_a
        else
          return included_data_for(name, relationship_definition)
        end
      end

      url = relationship_definition["links"]["related"]
      if relationship_definition["links"] && url
        return association_for(name).data(url)
      end

      nil
    end
  end
@senid231 senid231 self-assigned this Mar 26, 2019
@senid231 senid231 pinned this issue Mar 26, 2019
@code-bunny
Copy link
Author

Another oddity discovered required a wee bit more work.

class Foo < JsonApiClient::Resource
  property :fuzz
end

class Bar < JsonApiClient::Resource
  has_one :foo
  has_many :foos
end

bar = Bar.new
bar.foo = Foo.new(fuzz: "Buzz") #<Foo:@attributes={"type"=>"foos", "fuzz"=>"Buzz"}> 
bar.foo #<Foo:@attributes={"type"=>"foos", "id"=>nil}> 
bar.foo.fuzz #nil
bar.foos = [Foo.new(fuzz: "Buzz"), Foo.new(fuzz: "Buzz")] #[#<Foo:@attributes={"type"=>"foos", "fuzz"=>"Buzz"}>, #<Foo:@attributes={"type"=>"foos", "fuzz"=>"Buzz"}>]
bar.foos.first.fuzz #nil

@senid231
Copy link
Member

@code-bunny this is not an oddity.
According to spec client can send only relationship id and type
currently when you assign relationship to resource it only stores it's id and type
when you accessing relationship via getter method it recreates object according to id and type and cache it (for performance).

Can you give me usecase when you need to access relationship attributes of object which you currently create/update ?

@code-bunny
Copy link
Author

code-bunny commented Mar 26, 2019

@senid231 so an example where we would want to access the relationship before committing it is for instance when using a wizard like an order checkout.

class Item < JsonApiClient::Resource
  property :title
end

class Order < JsonApiClient::Resource
  include SomeStepWizard

  has_many :items
end

order = Order.new
order.step # 1
order.items = [Item.find(1).first]

order.next_step

# in some view
order.items.each { |item| puts "Thank you for wanting to buy #{item.title}" }

order.save

Basically when we assign a resource it should behave in the same was is if we had run an include on the endpoint. This would keep the behaviour consistent as demonstrated in my example.

bar = Bar.includes(:foo).find(1).first
bar.foo.hello # "world"

bar = Bar.new
bar.foo = Foo.find(1).first
bar.foo.hello # "world"

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

No branches or pull requests

2 participants