-
-
Save Kingdutch/299b3c6fd5702ad2ea50 to your computer and use it in GitHub Desktop.
| class BeersController < ApplicationController | |
| before_action :set_beer, only: [:show, :update, :destroy] | |
| # GET /beers | |
| def index | |
| @beers = Beer.all | |
| data = [] | |
| included = [] | |
| # set up the links for this request (e.g. self, next, last, etc.) | |
| links = { | |
| self: request.original_url | |
| } | |
| # massage the data into shape | |
| # TODO: Not all requests should return price, temporary or active | |
| should_include = { | |
| beer_types: Array.new | |
| } | |
| for beer in @beers | |
| entry = { | |
| type: 'beers', | |
| id: beer.id, | |
| attributes: { | |
| name: beer.name, | |
| description: beer.description, | |
| volume: beer.volume, | |
| alcohol: beer.alcohol, | |
| price: beer.price, | |
| temporary: beer.temporary, | |
| active: beer.active | |
| }, | |
| relationships: { | |
| beer_type: { | |
| # TODO: add dynamically generated links here | |
| data: { type: 'beer_types', id: beer.beer_types_id } | |
| } | |
| }, | |
| links: { | |
| # TODO: add dynamically generated link to self here | |
| } | |
| } | |
| should_include[:beer_types].push(beer.beer_types_id) | |
| data.push(entry) | |
| end | |
| print 'Beer types array:' | |
| puts should_include[:beer_types] | |
| # find the included beer types and pass them along | |
| @beer_types = BeerType.find(should_include[:beer_types].uniq) | |
| for type in @beer_types | |
| entry = { | |
| type: 'beer_types', | |
| id: type.id, | |
| attributes: { | |
| name: type.name, | |
| description: type.description | |
| }, | |
| links: { | |
| # TODO: add dynamically generated link to self here | |
| } | |
| } | |
| included.push(entry) | |
| end | |
| render json: { links: links, data: data, included: included } | |
| end | |
| # GET /beers/1 | |
| def show | |
| render json: @beer | |
| end | |
| # POST /beers | |
| def create | |
| @beer = Beer.new(beer_params) | |
| if @beer.save | |
| render json: @beer, status: :created, location: @beer | |
| else | |
| render json: @beer.errors, status: :unprocessable_entity | |
| end | |
| end | |
| # PATCH/PUT /beers/1 | |
| def update | |
| if @beer.update(beer_params) | |
| render json: @beer | |
| else | |
| render json: @beer.errors, status: :unprocessable_entity | |
| end | |
| end | |
| # DELETE /beers/1 | |
| def destroy | |
| @beer.destroy | |
| end | |
| private | |
| # Use callbacks to share common setup or constraints between actions. | |
| def set_beer | |
| @beer = Beer.find(params[:id]) | |
| end | |
| # Only allow a trusted parameter "white list" through. | |
| def beer_params | |
| params.require(:beer) | |
| .permit(:name, :beer_types_id, :volume, :alcohol, :price, | |
| :description, :temporary, :active) | |
| end | |
| end |
| class CreateBeers < ActiveRecord::Migration | |
| def change | |
| create_table :beers do |t| | |
| t.string :name, :null => false | |
| t.references :beer_types, index: true, foreign_key: true | |
| t.decimal :volume, :null => false | |
| t.decimal :alcohol, precision: 3, scale: 1, :null => false | |
| t.decimal :price, precision: 5, scale: 2, :null => false | |
| t.text :description, :null => false | |
| t.boolean :temporary, default: false | |
| t.boolean :active, default: true | |
| t.timestamps | |
| end | |
| add_index :beers, :name, unique: true | |
| end | |
| end |
| # This file should be in config/initializers -- don't copy this line | |
| # Be sure to restart your server when you modify this file. | |
| # Serialize models using AWS as json_api instead of plain json | |
| ActiveModel::Serializer.config.adapter = :json_api |
| class Beer < ActiveRecord::Base | |
| belongs_to :beer_types, class_name: 'BeerType' | |
| validates :name, :presence => true | |
| validates :volume, :presence => true | |
| validates :alcohol, :presence => true | |
| validates :price, :presence => true | |
| validates :description, :presence => true | |
| end |
| { | |
| "links": { | |
| "self": "http://localhost:3000/beers/" | |
| }, | |
| "data": [ | |
| { | |
| "type": "beers", | |
| "id": 1, | |
| "attributes": { | |
| "name": "Saison 1", | |
| "description": "The first Saison we have!", | |
| "volume": 0, | |
| "alcohol": "8.5", | |
| "price": "10.2", | |
| "temporary": false, | |
| "active": true | |
| }, | |
| "relationships": { | |
| "beer_type": { | |
| "data": { | |
| "type": "beer_types", | |
| "id": 1 | |
| } | |
| } | |
| }, | |
| "links": {} | |
| } | |
| ], | |
| "included": [ | |
| { | |
| "type": "beer_types", | |
| "id": 1, | |
| "attributes": { | |
| "name": "Saison", | |
| "description": "A pale ale that is generally around 7% abv, highly carbonated, fruity, spicy, and often bottle conditioned." | |
| }, | |
| "links": {} | |
| } | |
| ] | |
| } |
The beer_types model, migration and controller are all trivial and are thus omitted.
They can be created using rails g scaffold BeerType name:string:uniq description:text
The https://github.com/rails-api/active_model_serializers json_api serializer is probably more to our taste than the json_api gem which does a lot more magic. I need to find out how to set the serializers to json_api format.
Furthermore, there's extra loading of the BeerType model in the index method which is not needed in the show method. This is because the show method properly uses the serializer which is aware of the beertype and renders it correctly while the index method doesn't do this.
The jsonapi_serializer.rb file I just added changes the following:
{
"id": 1,
"name": "Saison 1",
"volume": 0,
"alcohol": "8.5",
"price": "10.2",
"description": "The first Saison we have!",
"active": true,
"beer_types": {
"id": 1,
"name": "Saison",
"description": "A pale ale that is generally around 7% abv, highly carbonated, fruity, spicy, and often bottle conditioned."
}
}
Into
{
"data": {
"id": "1",
"type": "beers",
"attributes": {
"name": "Saison 1",
"volume": 0,
"alcohol": "8.5",
"price": "10.2",
"description": "The first Saison we have!",
"active": true
},
"relationships": {
"beer_types": {
"data": {
"id": "1",
"type": "beer_types"
}
}
}
}
}
Which is pretty awesome
It tries to adhere to the JSON API standard but this creates controllers that do quite a lot of work.
It should be possible to refactor this and move work to the controller, although that might increase the number of database requests for Beer Types which is now just 1, meaning a listing of all beers involves just two requests.