/T /I
/ |/ | .-~/
T\ Y I |/ / _
/T | \I | I Y.-~/
I l /I T\ | | l | T /
__ | \l \l \I l __l l \ ` _. |
\ ~-l `\ `\ \ \\ ~\ \ `. .-~ |
\ ~-. "-. ` \ ^._ ^. "-. / \ |
.--~-._ ~- ` _ ~-_.-"-." ._ /._ ." ./
>--. ~-. ._ ~>-" "\\ 7 7 ]
^.___~"--._ ~-{ .-~ . `\ Y . / |
<__ ~"-. ~ /_/ \ \I Y : |
^-.__ ~(_/ \ >._: | l______
^--.,___.-~" /_/ ! `-.~"--l_ / ~"-.
(_/ . ~( /' "~"--,Y -=b-. _)
(_/ . \ : / l c"~o \
\ / `. . .^ \_.-~"~--. )
(_/ . ` / / ! )/
/ / _. '. .': / '
~(_/ . / _ ` .-<_
/_/ . ' .-~" `. / \ \ ,z=.
~( / ' : | K "-.~-.______//
"-,. l I/ \_ __{--->._(==.
//( \ < ~"~" //
/' /\ \ \ ,v=. ((
.^. / /\ " }__ //===- `
/ / ' ' "-.,__ {---(==-
.^ ' : T ~" ll
/ . . . : | :! \\
(_/ / | | j-" ~^
~-<_(_.^-~"
A library for writing authoritative representations of objects for pages and apis.
Add this line to your application's Gemfile:
gem 'rep'
And then execute:
$ bundle
Or install it yourself as:
$ gem install rep
include Rep
into any class. See nathanherald.com/rep for complete docs on every method.
# imagine Photo is an ActiveRecord model with fields for title, exif, location, and user_id
class PhotoRep
include Rep
initialize_with :photo
fields [:url, :title, :exif, :location, :user] => :default
forward [:title, :exif, :location] => :photo
forward :user => :user_rep
def url
full_photo_url(photo.name)
end
def user
UserRep.shared(user: photo.user)
end
end
# imagine User is an ActiveRecord model with fields for name, email, and location
class UserRep
include Rep
initialize_with :user
fields [:name, :email, :location] => :default
fields [:id, :admin].concat(fields(:default)) => :admin
forward fields(:admin) => :user
end
# You can now do crazy stuff like
UserRep.new(user: User.first).to_hash.keys # => [:name, :email, :location]
# To save from creating lots of objects, you can use a shared class that is reset fresh
UserRep.shared(user: User.first).to_hash # => { name: "Nathan Herald:, ...
# You can use class to proc (that makes a hash using the shared instance)
User.all.map(&UserRep) # => [{ name: "Nathan Herald" ...
# or maybe find all photos which will embed all users (and only ever make one instance each of PhotoRep and UserRep)
Photo.all.map(&PhotoRep).to_json
You don't have to have a Rep per model and Rep's can represent multiple objects at once. It's POROs.
class ProjectReport
include Rep
initialize_with :project, :active_users, :orders
fields [:name, :date, :count, :total_gross_cost, :cost_per_active_user] => :default
forward :date => :project
forward :count => :orders
def name
"#{project.name} Report"
end
def total_gross_cost
orders.reduce(0.0) { |memo, order| memo += order.total_gross_cost.to_f }
end
def cost_per_active_user
active_users.count.to_f / total_gross_cost.to_f
end
end
A possible controller
class PhotosController < ApplicationController
respond_to :json, :html
def index
@photos = Photo.paginate(page: params[:page], per_page: 20)
respond_with @photos.map(&PhotoRep)
end
def show
@photo = Photo.find(params[:id])
respond_with PhotoRep.new(photo: @photo)
end
end