Git Product home page Git Product logo

generic_controller's Introduction

Intent

To create a simple, light-weight, easy to override, and easy to understand boilerplate for standard controller actions.

Libraries

  • Rails 5
  • Active Model Serializers 0.10.2

Usage

class ApplicationController < ActionController::API
  include GenericActions
end

Now the controller has support for the basic index, show, create, update, and destroy actions. A find action that will return a single resource or 404 instead of a collection like the index action is also available.

Resources can be filtered and associations can be side-loaded in a single request. Simple header-based pagination is also included.

The param-based filtering and side-loading was inspired by the JSONAPI spec. The API for defining filters was inspired by JSONAPI::Resources.

Filtering

Creating a filter is done by using the filter method.

GET /customers?filter[first_name]=Joshua
class CustomersController < ApplicationController
  filter :first_name
end

If your filter needs to do something besides check equality:

class CustomersController < ApplicationController
  filter :first_name, -> (chain, value) do
    chain.where('first_name like ?', "%#{value}%")
  end
end

Filters are chained.

GET /customers?filter[first_name]=Joshua&filter[last_name]=Kappers
class CustomersController < ApplicationController
  filter :last_name
  filter :first_name
end
Side-loading

Thanks to Active Model Serializers, we can easily include association data in a single payload.

class Customer
  has_many :accounts
  has_many :addresses
end

class Account
  belongs_to :customer
  belongs_to :agency
end

class Address
  belongs_to :customer
end

class Agency
  has_many :accounts
end
GET /customers?include=accounts,addresses
{
  ...,
  "accounts": [],
  "addresses": []
}
GET /account/1?include=customer.addresses,agency
{
  ...,
  "customer": {
    "addresses": [],
  },
  "agency": {}
}
Do I have to define a serializer for every resource?

Nah, Active Model Serializers will handle it if you don't. It seems that for large payloads, defining a serializer speeds things up. I have not benchmarked this to be certain that is the case.

Pagination

The actual method for applying the filter was lifted from Kaminari.

Default page size is currently 50

GET /customers?page=2&size=10

HEADERS
  'X-Page' => 1,
  'X-Page-Size' => 10,
  'X-Page-Count' => 12,
  'X-Total' => 120
I don't like 50 as a page size >:(

Fine..

class ApplicationController
  include GenericActions

  def default_page_size
    25
  end
end

Why?

  1. I was tired of duplicating the same controller boilerplate.
  2. I used JSONAPI::Resources but...
  3. ...I had some problems with the JSONAPI spec.
What problems did you have with the spec?

First, there is no support for creating multiple entities in a single request. This was a huge problem for me and is a problem for many others. While there is a conversation and intent to include support in version 1.1, waiting is not an option. This is especially true considering the conversation is over a year old with seemingly no solution in sight.

I have tried several libraries and workarounds. My "favorite" workaround was to use Rails acccepts_nested_attributes_for along with JSONAPI::Resources.

While this wasn't too bad on the API, I found that library support for consuming the API is lacking.

I quickly realized I was sacrificing a lot of the productivity and duck-taping together libraries that weren't designed to work together, all for the sake of following a spec that doesn't add any value for my project or meet the needs of my project.

Rails' standard serialization has served me well and doesn't slow me down.

Was there anything you liked about JSONAPI::Resources or the spec?

Yes! The side-loading of associations in a single request is very handy. The filtering features were also very nice.

I want to move off of the spec and that library, but I want to keep those features, so I replicated them here.

generic_controller's People

Watchers

 avatar  avatar

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.