https://github.com/trailblazer/roar-rails
Use Roar's representers in Rails.
https://github.com/trailblazer/roar-rails
Last synced: 6 months ago
JSON representation
Use Roar's representers in Rails.
- Host: GitHub
- URL: https://github.com/trailblazer/roar-rails
- Owner: trailblazer
- License: mit
- Created: 2011-12-29T13:03:45.000Z (almost 14 years ago)
- Default Branch: master
- Last Pushed: 2024-01-09T13:09:38.000Z (over 1 year ago)
- Last Synced: 2025-03-30T05:08:03.422Z (6 months ago)
- Language: Ruby
- Homepage: http://roar.apotomo.de
- Size: 350 KB
- Stars: 235
- Watchers: 13
- Forks: 61
- Open Issues: 30
-
Metadata Files:
- Readme: README.markdown
- Changelog: CHANGES.markdown
- License: LICENSE
Awesome Lists containing this project
README
# roar-rails
_Makes using Roar's representers in your Rails app fun._
[](https://travis-ci.org/apotonick/roar-rails)
[](http://badge.fury.io/rb/roar-rails)_roar-rails development will be discontinued in the future and we will encourage users to begin migrating to [Trailblazer](http://trailblazer.to) (and [trailblazer-rails](https://github.com/trailblazer/trailblazer-rails))._
---
Roar is a framework for parsing and rendering REST documents. For a better overview about representers please check the [roar repository](https://github.com/trailblazer/roar#roar).
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
* GeneratorsThis gem works with all Rails >= 3.x.
## Prerequisites
Add it to your app's `Gemfile`.
```ruby
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.
```ruby
gem "responders"
gem "roar-rails"
```## Generators
The generator will create the representer modules in `app/representers` for you.
Here's an example.
```shell
rails g representer Band id name
```This will create the file `app/representers/band_representer.rb` with the following content,
```ruby
module BandRepresenter
include Roar::JSONproperty :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
```shell
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.
```ruby
class SingersController < ApplicationController
include Roar::Rails::ControllerAdditions
respond_to :jsondef 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:
```ruby
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.
```ruby
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.
```ruby
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.
```ruby
class SingersController < ApplicationController
include Roar::Rails::ControllerAdditions
include Roar::Rails::ControllerAdditions::Renderdef 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.
```ruby
class SingersController < ApplicationControllerdef 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.```ruby
class SingersController < ApplicationController
respond_to :jsondef 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.
```ruby
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.
```ruby
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.
```ruby
class SingerRepresenter < Roar::Decorator
include Roar::JSON
include Roar::Hypermediaproperty :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).
```ruby
respond_with @singer, :current_user => current_user
```Same goes with `#consume!`, passing options to `from_json`.
```ruby
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.
```ruby
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](https://github.com/apotonick/representable/#passing-options).
## URL Helpers
Any URL helpers from the Rails app are automatically available in representers.
```ruby
module FruitRepresenter
include Roar::JSON
include Roar::Hypermedialink :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):```ruby
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](https://groups.google.com/forum/?fromgroups#!topic/rubyonrails-core/5tG5unZ8jDQ) 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.
```ruby
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.
```ruby
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.
```ruby
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.
```ruby
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`:
```ruby
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:
```ruby
ActionController::Renderers.add :json_api do |obj, options|
self.content_type ||= Mime[:json_api]
obj
end
```
## Contributors* [Railslove](http://www.railslove.de) and especially Michael Bumann [bumi] have heavily supported development of roar-rails ("resource :singers").
[responders]: https://github.com/plataformatec/responders
## License
Roar-rails is released under the [MIT License](http://www.opensource.org/licenses/MIT).