Giter Site home page Giter Site logo

jsonapi_compliable's Introduction

JsonapiCompliable

Build Status

JSONAPI Suite Website

Documentation

Supported Rails versions: >= 4.1

Upgrading to 0.11.x

Due to a backwards-incompatibility introduced in the underlying jsonapi-rb gem, specifying custom serializers now works slightly differently.

Before:

# app/serializers/serializable_post.rb

has_many :comments, class: SerializableSpecialComment

and/or

render_jsonapi(post, class: SerializableSpecialPost)

This is now all handled at the controller level:

render_jsonapi(post, class: {
  Post: SerializableSpecialPost,
  Comment: SerializableSpecialComment
})

Upgrading to 0.10

sideload_whitelist has been moved from the resource to the controller:

class PostsController < ApplicationController
  jsonapi resource: PostResource do
-    sideload_whitelist({ index: [:foo] })
-  end
+  sideload_whitelist({ index: [:foo] })
end

# NEW

Running tests

We support Rails >= 4.1. To do so, we use the appraisal gem. So, run:

$ bin/appraisal rails-4 bin/rspec
$ bin/appraisal rails-5 bin/rspec

Or run tests for all versions:

$ bin/appraisal bin/rspec

Generating the Documentation

$ yard doc
$ yard server

jsonapi_compliable's People

Contributors

amitsuryavanshi avatar andrewo avatar angelinatarapko avatar aribouius avatar beauby avatar chanderhan avatar derekcannon avatar dishwasha avatar jsjohnst avatar jwrobes avatar ricardo-quinones avatar richmolj avatar stevenharman avatar wadetandy avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

jsonapi_compliable's Issues

Pass in config to adapters

We are building a custom adapter and the existing abstractions are very helpful in this process.

The one piece that would be nice is if the config option from the resource was automatically passed in to new adapters. Hacking this is simple enough, but we are finding several use cases (like storing additional configuration options in the resource and the adapter changing it's behavior based on certain filters).

Sideloading fails if (nested) sideloads have the same name

Suppose the following resources with the sideloading of author.identity and reviewer.identity

class PostResource
  belongs_to :author, resource: UserResource
  belongs_to :reviewer, resource: UserResource
end

class UserResource
  belongs_to :identity
end

class IdentityResource
end

Sideloading author.identity and reviewer.identity will fail on reviewer.identity since identity was already sideloaded for author and there is an early return (that originally protects from sideloading recursion) here

[Needs confirmation]

N+1 Query with Bullet

I am using https://github.com/flyerhzm/bullet to detect N+1 queries and anytime I use the JsonAPI Compliable resources with sideloading, it is "detecting" an N+1 query.

I believe this is because jsonapi_compliable eagerloads sideloaded assocations without using the .includes() method that bullet is trying to detect

Is there a way for this library to play nicely with bullet or other n+1 detectors - it's making our devs think we have N+1 queries when we dont.

no object in Resource

in a more complex scenario I want to access attributes of the @object in a Resource (just like in a Serializer). Is that possible somehow?

class UserResource
  type :users
  
  has_many :addresses,
    resource: AdressResource,
    foreign_key: :abc,
    primary_key: :xyz,
    scope -> { Adress.where("zip LIKE ?", @object.zip) }
end

N+1 Query Detected

I am using https://github.com/flyerhzm/bullet to detect N+1 queries and anytime I use the JsonAPI Compliable resources with sideloading, it is "detecting" an N+1 query.

I believe this is because jsonapi_compliable eagerloads sideloaded assocations without using the .includes() method that bullet is trying to detect

Is there a way for this library to play nicely with bullet or other n+1 detectors - it's making our devs think we have N+1 queries when we dont.

Posting to nested routes

In a case of /posts/1/comments and a payload

{data: {type: 'comments', attributes: { content: 'Some comment'}}}

I would like to be able to add the relationship to posts without the client having to specify the relationship in the payload. I really hope this is compliant with the spec.
How would I implement this in json_api compliable? jsonapi_create does not take any params, but it would be helpful if it did.

Attributes/Persistence logic does not support Mongoid HABTM

In Mongoid, has_and_belongs_to_many means storing an array of IDs in the document.
So the usual flow of updating a model attribute with a key doesn't make too much sense. Instead we need to add/remove keys`

class Tag
  has_many :profiles
end

class Profile
  has_and_belongs_to :tags
end

tags = FactoryGirl.create_list(:tags, 2)
profile = Profile.create(tags: tags)
profile.as_document
#=>
 {
 "_id"=>BSON::ObjectId('593ab877aba9cf64dbd09582'),
 "tag_ids"=>[
    BSON::ObjectId('592da071aba9cf502513d424'), 
    BSON::ObjectId('592da081aba9cf502513d426')
  ]
}

To begin with, there is a somewhat hardcoded list of has_many/belongs_to in the persistence class
https://github.com/jsonapi-suite/jsonapi_compliable/blob/master/lib/jsonapi_compliable/util/persistence.rb#L98

that should be moved to the adapter, so for mongoid I can override/implement it with a :habtm

Then for the persistence flow itself, I had to monkeypatch the update_foreign_key logic to support writing the list of habtm IDs

def update_foreign_key(parent_object, attrs, x)
    ...
    elsif x[:sideload].type == :habtm
      (attrs[x[:foreign_key]] ||= []) << parent_object.send(x[:primary_key]).to_s
    ...

Need to declare jsonapi resource: in every controller when inheriting mix-in from ApplicationController

Have a small issue where when the JsonapiSuite::ControllerMixin is being included in ApplicationController, descendant controllers which don't have a json resource: <name> declaration throw the following:

undefined method `new' for nil:NilClass
      @jsonapi_resource ||= self.class._jsonapi_compliable.new

The environment in this case is:

ApplicationController

  • MainController (welcome pages) <- error occurs on requests to this controller's views
  • LoginController <- error occurs on requests to this controller's views
  • CompaniesController <- has json resource: CompanyResource defined and no issues
  • UsersController <- has json resource: UserResource defined and no issues

Defining the mix-in only in the controllers where the jsonapi functions are being used bypasses this issue and all works as expected, however with the documentation recommending declaration in the ApplicationController this could be a gotcha for new users.

destroyed objects rendering

Looks like render_jsonapi(object)is not checking the object.destroyed? method and tries to serialize that object rather than returning no content with 204 or just meta with 200.
This is the spec part: http://jsonapi.org/format/#crud-deleting
I am more than willing to work on this if you share your ideas how and where you planned to implement this.

Association arguments and scope

It looks like all of the association helpers have scope default to nil, however later in the methods there are assumptions that it is not nil (e.g. _scope.call.where).

Would it be better to not set a default value?

having filter guards call controller method causes issues when resource is sideloaded

Unless the controller method used for a filter guard exists on all controllers a resource could be sideloaded from, using a guard on an allow_filter will break when the filtered resource is fetched through sideloading. Since changing jsonapi_compliable to call guard on resource rather than controller will created a backwards incompatible change, I'm reporting the issue rather than attempting to fix it.

Disassociating a required belongs_to should raise error

If Post has many Comments, and you try to sidepost disassociate a comment, it will silently fail. Instead, we should raise an expressive error message.

The issue is that Rails 5 defaults belongs_to to be required and will fail validation if the foreign key is nil. So we attempt to disassociate these objects, but no DB update is made. This error should be a 422 validation error but since these objects are already disassociate in memory we never know to do so.

Add association validation errors on unsuccessful sidepost

To recreate:

  • parent has_one child
  • patch parent with sidepost child method: update and invalid params

results in:

ActiveRecord::RecordNotSaved:Failed to save the new associated child as parent.send("#{association_name}=", child) tries to associate invalid child.

expect:

  • 422 with errors returned

Here's my monkeypatch

module JsonapiCompliable
  module Adapters
    # @see Adapters::Abstract
    class ActiveRecord < Abstract
      # When a has_many relationship, we need to avoid Activerecord implicitly
      # firing a query. Otherwise, simple assignment will do
      # @see Adapters::Abstract#associate
      def associate(parent, child, association_name, association_type)
        if association_type == :has_many
          associate_many(parent, child, association_name)
        elsif association_type == :habtm
          if parent.send(association_name).exists?(child.id)
            associate_many(parent, child, association_name)
          else
            parent.send(association_name) << child
          end
        elsif association_type == :has_one
          if child.valid?
            parent.send("#{association_name}=", child)
          else
            child.errors.full_messages.each do |message|
              parent.errors.add(association_name, message)
            end
          end
        elsif
          child.send("#{association_name}=", parent)
        end
      end
    end
  end
end

Detect N+1 Query

I am using https://github.com/flyerhzm/bullet to detect N+1 queries and anytime I use the JsonAPI Compliable resources with sideloading, it is "detecting" an N+1 query.

I believe this is because jsonapi_compliable eagerloads sideloaded assocations without using the .includes() method that bullet is trying to detect

Is there a way for this library to play nicely with bullet or other n+1 detectors - it's making our devs think we have N+1 queries when we dont.

Sequel adapter

Hi,
Any idea if you will add an Sequel adapter?
It's way faster than AR and works with non-Rails frameworks quite well.

No interface to discriminently disable pagination for resource

There are some cases where we want a query to not use the default pagination. Using JSORM we could use Scope.prototype.per to some large size, but this doesn't feel right. It would be better if we could do something like .per(-1) and have jsonapicompliable resources not use pagination for that query instance.

Docs not updated

I just tried the new version but wasn't able to get it running.

  • shall we use allow_sideload instead of includes whitelist: ?
  • what is causing the error ERROR: RuntimeError: you must override #order in an adapter subclass ?

We're looking forward for the updated docs https://jsonapi-suite.github.io/jsonapi_compliable

Thanks a lot

Attributes/Persistence not friendly to noSQL embedding

As discussed in the slack, embedded noSQL relationships are not easily integratable in JsonapiCompliable module.

The current logic assumes a foreign_key is required to save associations, however Mongoid's embeds_one and embeds_many do not require the foreign key but the parent object itself. The nested objects are directly added as an attribute hash to the parent_object. It is almost as if it behaved as an attribute (with the big difference that embedded records are identified by an ID, indexable, and a special Mongoid proxy allows to use Active Model scopes on embedded relations)

In a nutshell, the resource #create, #update, and maybe even #destroy methods need a way to access the parent_object of the relation.

Add a rollback method on resources to handle manually defining a transaction

When dealing with transactionless operations (MongoDB, ElasticSearch, etc.) it is not possible to redefine the transaction, yet it would make sense to have a rollback method that would yield the model that was created or updated (ie the return of the create/update method.

Based on that, it would become possible to either destroy or just rollback the changes manually (ActiveModel has a nice previous_changes builtin method)

class FooResource

  def create(attributes)
    Foo.create(attributes)
  end

  def rollback(resource:, method:)
    if method == :create
      resource.destroy
    else
      resource.update_attributes(resource.previous_changes)
    end 
  end

The idea being that the rollback method would be fired automatically if there is for example a failure while persisting the related resources / sideposting

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.