• Stars
    star
    235
  • Rank 171,079 (Top 4 %)
  • Language
    Ruby
  • License
    MIT License
  • Created almost 13 years ago
  • Updated 10 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Use Roar's representers in Rails.

roar-rails

Makes using Roar's representers in your Rails app fun.

Build Status Gem Version

roar-rails development will be discontinued in the future and we will encourage users to begin migrating to Trailblazer (and trailblazer-rails).


Roar is a framework for parsing and rendering REST documents. For a better overview about representers please check the roar repository.

Roar-rails gives you conventions and convenient access to a lot of Roar's functionality within your Rails app.

Features

  • Rendering with responders
  • Parsing incoming documents
  • URL helpers in representers
  • Better tests
  • Autoloading
  • Generators

This gem works with all Rails >= 3.x.

Prerequisites

Add it to your app's Gemfile.

gem "roar-rails"

Note: For Rails >= 4.2, you need to add the responders gem, too, if you use respond_with. This has to be before the roar-rails entry in the Gemfile.

gem "responders"
gem "roar-rails"

Generators

The generator will create the representer modules in app/representers for you.

Here's an example.

rails g representer Band id name

This will create the file app/representers/band_representer.rb with the following content,

  module BandRepresenter
    include Roar::JSON

    property :id
    property :name
  end

You can change the format (e.g. XML), and pass arbitrary options to customize the generated representer. For all available options, just run

rails g representer

Rendering with #respond_with

roar-rails provides a number of baked-in rendering methods.

Conventional Rendering

Easily render resources using representers with the built-in responder.

class SingersController < ApplicationController
  include Roar::Rails::ControllerAdditions
  respond_to :json

  def show
    singer = Singer.find_by_id(params[:id])
    respond_with singer
  end
end

The representer name will be infered from the passed model class (e.g. a Singer instance gets the SingerRepresenter). If the passed model is a collection it will be extended using a representer. The representer name will be computed from the controller name (e.g. a SingersController uses the SingersRepresenter).

Need to use a representer with a different name than your model? You may always pass it in using the :represent_with option:

respond_with singers, :represent_with => MusicianCollectionRepresenter
end

Represents Configuration

If you don't want to use conventions or pass representers you can configure them on the class level using ::represents. This will also call respond_to for you.

class SingersController < ApplicationController
  represents :json, Musician

This will use the MusicianRepresenter for models and MusiciansRepresenter for representing collections.

Note that ::represents also allows fine-tuning.

class SingersController < ApplicationController
  represents :json, :entity => MusicianRepresenter, :collection => MusicianCollectionRepresenter

You might pass strings as representer names to ::represents, they will be constantized at run-time when needed.

Rendering with #render

In place of #respond_with, you can also use #render to serialize objects using representers.

class SingersController < ApplicationController
  include Roar::Rails::ControllerAdditions
  include Roar::Rails::ControllerAdditions::Render

  def show
    singer = Singer.find_by_id(params[:id])
    render json: singer
  end
end

Old API Support

If you don't want to write a dedicated representer for a collection of items (highly recommended, thou) but rather use a representer for each item, use the :represent_items_with option.

class SingersController < ApplicationController

  def index
    singers = Musician.find(:all)
    respond_with singers, :represent_items_with => SingerRepresenter
  end
end

Parsing incoming documents

In #create and #update actions it is often necessary to parse the incoming representation and map it to a model instance. Use the #consume! method for this. The client must provide a Content-Type request header with proper MIME type to let #consume! know which representer to use.

class SingersController < ApplicationController
  respond_to :json

  def create
    singer = Singer.new
    consume!(singer)

    respond_with singer
  end
end

For instance, if content type is set to application/xml the consume! call will roughly do the following.

singer.
  extend(SingerRepresenter)
  from_xml(request.body)

So, #consume! helps you figuring out the representer module and reading the incoming document. Just like Rails, depending on the registered MIME type for Content-type it picks the deserialize method (e.g. from_json vs. from_xml)

It is important to provide a known content type in the request. If it is missing or not supported by the responder #consume! will raise an exception Roar::Rails::ControllerAdditions::UnsupportedMediaType. Unless you rescue the exception the action will stop and respond with HTTP status 406 Unsupported Media Type.

Note that #consume! respects settings from #represents. It uses the same mechanics known from #respond_with to choose a representer.

consume!(singer, :represent_with => MusicianRepresenter)

Using Decorators

If you prefer roar's decorator approach over extend, just go for it. roar-rails will figure out automatically which represent strategy to use. Be sure to use roar >= 0.11.17.

class SingerRepresenter < Roar::Decorator
  include Roar::JSON
  include Roar::Hypermedia

  property :name

  link :self do
    singer_url(represented)
  end
end

In decorators' link blocks you currently have to use represented to get the actual represented model (this is self in module representers).

Passing Options

Both rendering and consuming support passing user options to the representer.

With #respond_with, any additional options will be passed to to_json (or whatever format you're using).

respond_with @singer, :current_user => current_user

Same goes with #consume!, passing options to from_json.

consume! Singer.new, :current_user => current_user

Note: If you pass in options to a representer, you must process them youself. For rendering, use :getter in the representer.

property :username, getter: lambda { |args| args[:current_user].name }

That'll render the current_user's name as the username property.

More docs about passing and processing option can be found here.

URL Helpers

Any URL helpers from the Rails app are automatically available in representers.

module FruitRepresenter
  include Roar::JSON
  include Roar::Hypermedia

  link :self do
    fruit_url self
  end
end

To get the hyperlinks up and running, please make sure to set the right host name in your environment files (config/environments):

config.representer.default_url_options = {:host => "127.0.0.1:3000"}

Attention: If you are using representers from a gem your Rails URL helpers might not work in these modules. This is due to a loading order problem in Rails. As a workaround, don't require the representers in the gem but load them as late as possible, usually it works when you require in the controller. We are working on fixing that problem.

Representing Formats Exclusively

By default, roar-rails will extend/decorate any model passed to respond_with for any request format. When adding roar-rails to a legacy project, you might want to restrict roar-rails' representing and fall back to the old behavior for certain formats. This can be configured both globally and on a per action basis.

To restrict representing globally to a particular format you can set the config.representer.represented_formats in your environment's configuration to an array of formats. For example the following will only represent hal and json requests.

config.representer.represented_formats = [:hal, :json]

The global configuration (or lack thereof) can be overridden by supplying the :represented_formats array when calling respond_with. The following will only represent @resource for the hal format in the show action. For any other format, it will expose the resource using Rails' old behavior.

class MyController < ApplicationController
  def show
    ...
    respond_with @resource, :represented_formats => [:hal]
  end
end

You can entirely suppress roar-rails in respond_with by passing in an empty array.

class MyController < ApplicationController
  def show
    ...
    respond_with @resource, :represented_formats => []
  end
end

Testing

Autoloading

Put your representers in app/representers and they will be autoloaded by Rails. Also, frequently used modules as media representers and features don't need to be required manually.

JSON-API

In a JSON-API environment, only one representer is written for both singular and collection resources. However, you have to configure represents accordingly so it knows what representer to use for collections.

class SongsController < ApplicationController
  represents :json_api, entity: SongRepresenter, collection: SongRepresenter.for_collection

Rails 4.1+ and HAL/JSON-API

Note: this is a temporary work-around, we're trying to fix that in Rails/roar-rails itself [May 2014].

Rails 4.1 and up expects you to manually register a global HAL or JSON-API renderer, or respond_with will throw an ActionController::MissingRenderer exception.

One fix is to add this to config/initializers/mime_types.rb right below Mime::Type.register 'application/hal+json', :hal:

ActionController::Renderers.add :hal do |obj, options|
  self.content_type ||= Mime[:hal]
  obj
end

Similarly, for JSON-API, below Mime::Type.register 'application/vnd.api+json', :json_api add:

ActionController::Renderers.add :json_api do |obj, options|
  self.content_type ||= Mime[:json_api]
  obj
end

Contributors

  • Railslove and especially Michael Bumann [bumi] have heavily supported development of roar-rails ("resource :singers").

License

Roar-rails is released under the MIT License.

More Repositories

1

trailblazer

The advanced business logic framework for Ruby.
Ruby
3,417
star
2

cells

View components for Ruby and Rails.
Ruby
3,057
star
3

reform

Form objects decoupled from models.
Ruby
2,494
star
4

roar

Parse and render REST API documents using representers.
Ruby
1,851
star
5

trailblazer-rails

Trailblazer in Rails.
Ruby
178
star
6

reform-rails

Automatically load and include all common Rails form features.
Ruby
99
star
7

trailblazer-operation

Trailblazer's Operation implementation.
Ruby
86
star
8

formular

Form builder for Ruby. Fast, Furious, and Framework-Agnostic.
Ruby
81
star
9

trailblazer-activity

Model business workflows and run them.
Ruby
70
star
10

cells-rails

Rails support for Cells.
Ruby
54
star
11

roar-jsonapi

JSON API support for Roar.
Ruby
42
star
12

trailblazer-finder

Find, filter and aggregate via ActiveRecord or Sequel.
Ruby
37
star
13

trailblazer-cells

Trailblazer's file structure for Cells.
Ruby
26
star
14

rspec-trailblazer

RSpec Matchers for strong and non-verbose operation tests.
Ruby
24
star
15

trailblazer-endpoint

Generic HTTP endpoints to deal with different results from your operations.
Ruby
23
star
16

trailblazer.github.io

The TRAILBLAZER.TO website. Please PR against the f6 branch. ๐Ÿ’‹
HTML
23
star
17

guides

Finally! Learn everything about operations, Trailblazer, Reform and Cells with our guides.
Ruby
21
star
18

trailblazer-loader

Require concept files, models and more without any autoloading magic.
Ruby
17
star
19

cells-slim

Ruby
17
star
20

tamarama

The stack we fancy: Sinatra/Grape, Trailblazer, Cells and Sequel.
Ruby
13
star
21

trailblazer-developer

Debugging, tracing and workflow management tools for Trailblazer developers.
Ruby
13
star
22

trailblazer-activity-dsl-linear

Simple DSL to compile Trailblazer activities.
Ruby
11
star
23

trailblazer-test

Super strong, non-verbose tests for your operations.
Ruby
11
star
24

trailblazer-generator

CLI generators for operations, contracts, cells, and much more.
Ruby
10
star
25

trailblazer-compat

This gem provides a seamless-erโ„ข upgrade from TRB 1.1 to 2.x.
Ruby
10
star
26

trailblazer-macro

Ruby
9
star
27

cells-erb

ERB support for Cells.
Ruby
9
star
28

cells-hamlit

Hamlit integration for Cells
Ruby
8
star
29

trailblazer-macro-contract

Reform and Dry::Validation integration for Trailblazer's operation.
Ruby
6
star
30

cells-haml

Haml integration for Cells
Ruby
5
star
31

blog-example

A publishing workflow implemented with Trailblazer.
Ruby
5
star
32

api-docs

Website for Trailblazer >= 2.1.
JavaScript
5
star
33

tutorial

The code for our tutorials.
Ruby
4
star
34

trailblazer-story

Painless test factories. / ...like a mix of cucumber and traits - delicious!
Ruby
3
star
35

website

The trailblazer.to website
HTML
3
star
36

trailblazer-context

Argument-specific data structures for Trailblazer.
Ruby
3
star
37

meta

Ruby
3
star
38

cells-mailer

Provides mail functionality for the Cells gem.
Ruby
3
star
39

trailblazer-transform

Transform, parse, coerce, validate, it's all just a chain of transformations. Replacement/extension for Reform.
Ruby
3
star
40

trailblazer-disposable

Domain object layer.
Ruby
2
star
41

tyrant

Authentication library.
Ruby
2
star
42

trailblazer-option

Generate callables in Trailblazer!
Ruby
2
star
43

cfp-app

Ruby
1
star
44

trailblazer-declarative

Generic DSL providing schemas and inheritance.
Ruby
1
star
45

trailblazer-errors

Generic errors object used in operations and contracts.
Ruby
1
star
46

trailblazer-pro-rails

Rails support for TRB PRO.
Ruby
1
star
47

blog9

Blog application with approve/reject workflow.
Ruby
1
star
48

trailblazer-future

Bridge gem to upgrade from 2.0 to 2.1
Ruby
1
star
49

trailblazer-args

Scoped, mutable and immutable keyword arguments for callables.
Ruby
1
star