toast 0.6.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README.md CHANGED
@@ -1,32 +1,31 @@
1
1
  Summary
2
2
  =======
3
3
 
4
- Toast is an extension to Ruby on Rails that lets you expose any
5
- ActiveRecord model as a resource according to the REST paradigm. The
6
- representation format is JSON.
4
+ Toast is an extension to Ruby on Rails to build web services with low
5
+ programming effort in a coherent way. Toast exends ActiveRecord such
6
+ that each model can be declared to be a web resource, exposing defined
7
+ attributes for reading and writing using HTTP.
7
8
 
8
- In contrast to other plugins, gems and Rails' inbuilt REST features
9
- toast takes a data centric approach: Tell the model to be a resource
10
- and what attributes and associations are to be exposed. That's it. No
11
- controller boiler plate code for every model, no routing setup.
9
+ Its main features are:
12
10
 
13
- Toast is a Rails engine that runs one generic controller and a sets up
14
- the routing according to the definition in the models, which is
15
- denoted using a block oriented DSL.
11
+ * declaration of web resources based on ActiveRecord models
12
+ * generic controller handles all actions
13
+ * automated routing
14
+ * exposing data values with JSON maps
15
+ * exposing associations by links (URLs)
16
16
 
17
- REST is more than some pretty URIs, the use of the HTTP verbs and
18
- response codes. It's on the toast user to invent media types that
19
- control the application's state and introduce semantics. With toast you
20
- can build REST services or tightly coupled server-client applications,
21
- which ever suits the task best. That's why TOAST stands for:
17
+ Toast works with Ruby on Rails >= 3.1.0 (currently tested up to 3.2.6)
22
18
 
23
- > **TOast Ain't reST**
19
+ WARNING
20
+ =======
21
+
22
+ This version is experimental and probably not bullet
23
+ proof. As soon as the gem is loaded a controller with ready routing is
24
+ enabled serving the annotated model's data records.
24
25
 
25
- *Be careful*: This version is experimental and probably not bullet
26
- proof. As soon as the gem is loaded a controller with ready routing
27
- is enabled serving the annotated model's data records for reading,
28
- updating and deleting. There are no measures to prevent XSS and CSFR
29
- attacks.
26
+ Version 1.0.0 of Toast is planned to be a production-ready implementation,
27
+ which will be finished within 2012. Until then API/DSL changes must
28
+ be expected with each minor update.
30
29
 
31
30
  Example
32
31
  =======
@@ -40,89 +39,89 @@ Let the table `bananas` have the following schema:
40
39
  t.integer "apple_id"
41
40
  end
42
41
 
43
- and let a corresponding model class have a *resourceful_model* annotation:
42
+ and let a corresponding model class have a *acts_as_resource* annotation:
44
43
 
45
44
  class Banana < ActiveRecord::Base
46
45
  belongs_to :apple
47
46
  has_many :coconuts
48
- scope :find_some, where("number < 100")
47
+
48
+ scope :less_than_100, where("number < 100")
49
49
 
50
- resourceful_model do
51
- # attributes or association names
50
+ acts_as_resource do
51
+ # exposed attributes or association names
52
52
  readables :coconuts, :apple
53
- writables :name, :number
53
+ writables :name, :number
54
54
 
55
- # class methods of Banana returning an Array of Banana records
56
- collections :find_some, :all
55
+ # exposed class methods of Banana returning an Array of Banana records
56
+ collections :less_than_100, :all
57
57
  end
58
58
  end
59
59
 
60
- The above definition inside the `resourceful_model` block exposes the
60
+ The above definition inside the `acts_as_resource` block exposes the
61
61
  records of the model Banana automatically via a generic controller to
62
62
  the outside world, accepting and delivering JSON representations of
63
63
  the records. Let the associated models Apple and Coconut be
64
- exposed as a resource, too.
64
+ exposed as a resource, too:
65
65
 
66
66
  ### Get a collection
67
67
  GET /bananas
68
- --> 200, '[{"uri":"http://www.example.com/bananas/23",
69
- "name": "Fred",
70
- "number": 33,
68
+ --> 200, '[{"self": "http://www.example.com/bananas/23",
69
+ "name": "Fred",
70
+ "number": 33,
71
71
  "coconuts": "http://www.example.com/bananas/23/coconuts",
72
- "apple":"http://www.example.com/bananas/23/apple,
73
- {"uri":"http://www.example.com/bananas/24",
72
+ "apple": "http://www.example.com/bananas/23/apple,
73
+ {"self": "http://www.example.com/bananas/24",
74
74
  ... }, ... ]
75
75
  ### Get a customized collection (filtered, paging, etc.)
76
-
77
- GET /bananas/find_some
78
- --> 200, '[SOME BANANAS]'
76
+ GET /bananas/less_than_100
77
+ --> 200, '[{BANANA}, {BANANA}, ...]'
79
78
 
80
79
  ### Get a single resource representation:
81
80
  GET /bananas/23
82
- --> 200, '{"uri":"http://www.example.com/bananas/23"
83
- "name": "Fred",
84
- "number": 33,
81
+ --> 200, '{"self": "http://www.example.com/bananas/23"
82
+ "name": "Fred",
83
+ "number": 33,
85
84
  "coconuts": "http://www.example.com/bananas/23/coconuts",
86
- "apple": "http://www.example.com/bananas/23/apple" }'
85
+ "apple": "http://www.example.com/bananas/23/apple" }'
87
86
 
88
- ### Get a associated collection
87
+ ### Get an associated collection
89
88
  "GET" /bananas/23/coconuts
90
89
  --> 200, '[{COCNUT},{COCONUT},...]',
91
90
 
92
91
  ### Update a single resource:
93
- PUT /bananas/23, '{"uri":"http://www.example.com/bananas/23"
94
- "name": "Barney",
92
+ PUT /bananas/23, '{"self": "http://www.example.com/bananas/23"
93
+ "name": "Barney",
95
94
  "number": 44}'
96
- --> 200, '{"uri":"http://www.example.com/bananas/23"
97
- "name": "Barney",
98
- "number": 44,
95
+ --> 200, '{"self": "http://www.example.com/bananas/23"
96
+ "name": "Barney",
97
+ "number": 44,
99
98
  "coconuts": "http://www.example.com/bananas/23/coconuts",
100
- "apple": "http://www.example.com/bananas/23/apple"}'
99
+ "apple": "http://www.example.com/bananas/23/apple"}'
101
100
 
102
101
  ### Create a new record
103
102
  "POST" /bananas, '{"name": "Johnny",
104
103
  "number": 888}'
105
- --> 201, {"uri":"http://www.example.com/bananas/102"
106
- "name": "Johnny",
107
- "number": 888,
104
+ --> 201, {"self": "http://www.example.com/bananas/102"
105
+ "name": "Johnny",
106
+ "number": 888,
108
107
  "coconuts": "http://www.example.com/bananas/102/coconuts" ,
109
- "apple": "http://www.example.com/bananas/102/apple }
108
+ "apple": "http://www.example.com/bananas/102/apple }
110
109
 
111
110
  ### Create an associated record
112
111
  "POST" /bananas/23/coconuts, '{COCONUT}'
113
- --> 201, {"uri":"http://www.example.com/coconuts/432,
112
+ --> 201, {"self":"http://www.example.com/coconuts/432,
114
113
  ...}
115
114
 
116
115
  ### Delete records
117
116
  DELETE /bananas/23
118
117
  --> 200
119
118
 
120
- More details and configuration options are documented in the manual... (_comming soon_)
119
+ More details and configuration options are documented in the manual.
121
120
 
122
121
  Installation
123
122
  ============
124
123
 
125
- With bundler
124
+ With bundler from (rubygems.org)
126
125
 
127
126
  gem "toast"
128
127
 
@@ -130,29 +129,14 @@ the latest Git:
130
129
 
131
130
  gem "toast", :git => "https://github.com/robokopp/toast.git"
132
131
 
133
- Test Suite
134
- ==========
135
-
136
- In `test/rails_app` you can find a rails application with tests. To run
137
- the tests you need to
138
-
139
- 0. Install the *jeweler* gem:
140
-
141
- gem install jeweler
142
-
143
- 1. install the toast gem from this git clone:
144
-
145
- rake install
146
-
147
- 2. initialize the test application
148
-
149
- cd test/rails_app
150
- bundle install
151
-
152
- 3. Now you can run the test suite from within the test application
132
+ Remarks
133
+ =======
153
134
 
154
- rake
135
+ REST is more than some pretty URIs, the use of the HTTP verbs and
136
+ response codes. It's on the Toast user to invent meaningful media
137
+ types that control the application's state and introduce
138
+ semantics. With toast you can build REST services or tightly coupled
139
+ server-client applications, which ever suits the task best. That's why
140
+ TOAST stands for:
155
141
 
156
- Or you may call `rake test` from the root directory of the working
157
- copy. This will reinstall the toast gem before running tests
158
- automatically.
142
+ > **TOast Ain't reST**
@@ -25,7 +25,7 @@ class ToastController < ApplicationController
25
25
 
26
26
  rescue Exception => e
27
27
  log_exception e
28
- raise e if Rails.env == "test"
28
+ puts e if Rails.env == "test"
29
29
  return head(:internal_server_error)
30
30
  end
31
31
 
data/config/routes.rb CHANGED
@@ -14,7 +14,7 @@ Rails.application.routes.draw do
14
14
 
15
15
  namespaces << tc.namespace
16
16
 
17
- match("#{tc.namespace}/#{resource_name}(/:id(/:subresource))" => 'toast#catch_all',
17
+ match("#{tc.namespace}/#{resource_name}(/:id(/:subresource(/:scope)))" => 'toast#catch_all',
18
18
  :constraints => { :id => /\d+/ },
19
19
  :resource => resource_name,
20
20
  :as => resource_name,
@@ -44,15 +44,28 @@ module Toast
44
44
  # Like ActiveRecord::Base.attributes, but result Hash includes
45
45
  # only attributes from the list _attr_names_ plus the
46
46
  # associations _assoc_names_ as links and the 'self' link
47
- def represent attr_names, assoc_names, base_uri
47
+ def represent attr_names, assoc_names, base_uri, media_type
48
48
  props = {}
49
49
 
50
50
  attr_names.each do |name|
51
+ unless self.respond_to?(name) && self.method(name).arity == 0
52
+ raise "Toast Error: Connot find instance method '#{self.class}##{name}' of arity 0"
53
+ end
51
54
  props[name] = self.send(name)
52
55
  end
53
56
 
54
57
  assoc_names.each do |name|
55
58
  props[name] = "#{base_uri}#{self.uri_path}/#{name}"
59
+
60
+ # collections (scopes) actiing on associacions:
61
+
62
+ reflect = self.class.reflect_on_association(name.to_sym)
63
+ if reflect.collection?
64
+ reflect.klass.toast_config(media_type).collections.each do |collection_name|
65
+ next if collection_name == "all"
66
+ props[name+":"+collection_name] = "#{base_uri}#{self.uri_path}/#{name}/#{collection_name}"
67
+ end
68
+ end
56
69
  end
57
70
 
58
71
  props["self"] = base_uri + self.uri_path
@@ -22,6 +22,11 @@ module Toast
22
22
  end
23
23
 
24
24
  def get
25
+
26
+ unless @record.class.reflect_on_all_associations.detect{|a| a.name.to_s == @assoc}
27
+ raise "Toast Error: Association '#{@assoc}' not found in model '#{@record.class}'"
28
+ end
29
+
25
30
  result = @record.send(@assoc)
26
31
 
27
32
  raise ResourceNotFound if result.nil?
@@ -31,7 +36,8 @@ module Toast
31
36
  :json => result.map{|r|
32
37
  r.represent( @associate_config_out.in_collection.exposed_attributes,
33
38
  @associate_config_out.in_collection.exposed_associations,
34
- @base_uri )
39
+ @base_uri,
40
+ @associate_config_out.media_type )
35
41
  },
36
42
  :status => :ok,
37
43
  :content_type => @associate_config_out.in_collection.media_type
@@ -40,7 +46,8 @@ module Toast
40
46
  {
41
47
  :json => result.represent( @associate_config_out.exposed_attributes,
42
48
  @associate_config_out.exposed_associations,
43
- @base_uri ),
49
+ @base_uri,
50
+ @associate_config_out.media_type),
44
51
  :status => :ok,
45
52
  :content_type => @associate_config_out.media_type
46
53
  }
@@ -81,7 +88,8 @@ module Toast
81
88
  {
82
89
  :json => record.represent( @associate_config_out.exposed_attributes,
83
90
  @associate_config_out.exposed_associations,
84
- @base_uri ),
91
+ @base_uri,
92
+ @associate_config_out.media_type),
85
93
  :location => self.base_uri + record.uri_path,
86
94
  :status => :created,
87
95
  :content_type => @associate_config_out.media_type
@@ -3,7 +3,7 @@ module Toast
3
3
 
4
4
  attr_reader :model
5
5
 
6
- def initialize model, subresource_name, params, config_in, config_out
6
+ def initialize model_or_relation, subresource_name, params, config_in, config_out
7
7
 
8
8
  subresource_name ||= "all"
9
9
 
@@ -11,7 +11,11 @@ module Toast
11
11
  raise ResourceNotFound
12
12
  end
13
13
 
14
- @model = model
14
+ @target_model = (model_or_relation.klass rescue false) ?
15
+ model_or_relation.klass :
16
+ model_or_relation
17
+
18
+ @model_or_relation = model_or_relation
15
19
  @collection = subresource_name
16
20
  @params = params
17
21
  @format = params[:format]
@@ -21,24 +25,43 @@ module Toast
21
25
 
22
26
  def get
23
27
 
24
- records = if @config_out.pass_params_to.include?(@collection)
25
- @model.send(@collection, @params)
28
+ unless @model_or_relation.respond_to?(@collection)
29
+ raise "Toast Error: Cannot find class method '#{@collection}' of model '#{@model_or_relation}', which is configured in 'acts_as_resource > collections'."
30
+ end
31
+
32
+ # FIXME: This is a lot of hallooballoo to check if the #send
33
+ # will be successful, but if it's not checked the error
34
+ # message is not helpful to find the error.
35
+
36
+ records = if @config_out.pass_params_to.include?(@collection)
37
+ if @target_model.method(@collection).arity != 1
38
+ raise "Toast Error: Class method '#{@collection}' of model '#{@target_model}' must accept one parameter, as configured by 'acts_as_resource > pass_params_to'."
39
+ end
40
+ # fetch results
41
+ @model_or_relation.send(@collection, @params)
42
+
26
43
  else
27
- @model.send(@collection)
44
+
45
+ if @target_model.method(@collection).arity > 0
46
+ raise "Toast Error: Class method '#{@collection}' of model '#{@model_or_relation}' must not accept any parameter, as configured by 'acts_as_resource'"
47
+ end
48
+ # fetch results
49
+ @model_or_relation.send(@collection)
28
50
  end
29
51
 
30
52
  case @format
31
53
  when "html"
32
54
  {
33
- :template => "resources/#{model.to_s.pluralize.underscore}",
34
- :locals => { model.to_s.pluralize.underscore.to_sym => records }
55
+ :template => "resources/#{@target_model.to_s.pluralize.underscore}",
56
+ :locals => { @target_model.to_s.pluralize.underscore.to_sym => records }
35
57
  }
36
58
  when "json"
37
59
  {
38
60
  :json => records.map{|r|
39
61
  r.represent( @config_out.in_collection.exposed_attributes,
40
62
  @config_out.in_collection.exposed_associations,
41
- @base_uri )
63
+ self.base_uri,
64
+ @config_out.media_type)
42
65
  },
43
66
  :status => :ok,
44
67
  :content_type => @config_out.in_collection.media_type
@@ -78,13 +101,14 @@ module Toast
78
101
  end
79
102
 
80
103
  begin
81
- record = @model.create! payload
104
+ record = @model_or_relation.create! payload
82
105
 
83
106
  {
84
107
  :json => record.represent( @config_out.exposed_attributes,
85
108
  @config_out.exposed_associations,
86
- @base_uri ),
87
- :location => @base_uri + record.uri_path,
109
+ self.base_uri,
110
+ @config_out.media_type),
111
+ :location => self.base_uri + record.uri_path,
88
112
  :status => :created,
89
113
  :content_type => @config_out.media_type
90
114
  }
data/lib/toast/engine.rb CHANGED
@@ -4,6 +4,7 @@ require 'toast/collection'
4
4
  require 'toast/association'
5
5
  require 'toast/record'
6
6
  require 'toast/single'
7
+ require 'toast/scoped_association'
7
8
 
8
9
  require 'action_dispatch/http/request'
9
10
  require 'rack/accept_media_types'
data/lib/toast/record.rb CHANGED
@@ -41,6 +41,11 @@ module Toast
41
41
 
42
42
  # set the virtual attributes
43
43
  (@config_in.writables - @record.attribute_names - @config_in.exposed_associations).each do |vattr|
44
+
45
+ unless (@record.respond_to?("#{vattr}=") && @record.method("#{vattr}=").arity == 1)
46
+ raise "Toast Error: Connot find setter '#{@record.class}##{vattr}='"
47
+ end
48
+
44
49
  @record.send("#{vattr}=", payload.delete(vattr))
45
50
  end
46
51
 
@@ -49,7 +54,8 @@ module Toast
49
54
  {
50
55
  :json => @record.represent( @config_out.exposed_attributes,
51
56
  @config_out.exposed_associations,
52
- @base_uri ),
57
+ @base_uri,
58
+ @config_out.media_type ),
53
59
  :status => :ok,
54
60
  :location => self.base_uri + @record.uri_path,
55
61
  :content_type => @config_out.media_type
@@ -67,7 +73,8 @@ module Toast
67
73
  {
68
74
  :json => @record.represent( @config_out.exposed_attributes,
69
75
  @config_out.exposed_associations,
70
- @base_uri ),
76
+ @base_uri,
77
+ @config_out.media_type),
71
78
  :status => :ok,
72
79
  :content_type => @config_out.media_type
73
80
  }
@@ -22,11 +22,7 @@ module Toast
22
22
  id = params[:id]
23
23
  subresource_name = params[:subresource]
24
24
  format = params[:format]
25
-
26
- #### Debugging stop
27
- # binding.pry if $halt
28
- ###
29
-
25
+ scope = params[:scope]
30
26
  begin
31
27
 
32
28
  # determine model
@@ -39,7 +35,7 @@ module Toast
39
35
  config_in = model.toast_config request.media_type
40
36
 
41
37
  # ... or in case of an association request
42
- config_assoc_src = model.toast_config request.headers["Assoc-source-type"]
38
+ config_assoc_src = model.toast_config request.headers["Assoc-source-type"] # ?
43
39
 
44
40
  # base URI for returned object
45
41
  base_uri = request.base_url + request.script_name +
@@ -53,9 +49,10 @@ module Toast
53
49
  elsif subresource_name.nil?
54
50
  Toast::Record.new(model, id, format, config_in, config_out)
55
51
  elsif (config_assoc_src && config_assoc_src.exposed_associations.include?(subresource_name))
56
-
52
+
57
53
  # determine associated model
58
- assoc_model = get_class_by_resource_name subresource_name
54
+ assoc_model =
55
+ model.reflect_on_all_associations.detect{|a| a.name.to_s == subresource_name}.klass
59
56
 
60
57
  # determine config for representation of assoc. model
61
58
  assoc_config_out = assoc_model.toast_config request.accept_media_types.prefered
@@ -65,8 +62,13 @@ module Toast
65
62
  base_uri = request.base_url + request.script_name +
66
63
  (assoc_config_out.namespace ? "/" + assoc_config_out.namespace : "")
67
64
 
68
- Toast::Association.new(model, id, subresource_name, format, config_assoc_src,
69
- assoc_model, assoc_config_in, assoc_config_out)
65
+ if scope.nil?
66
+ Toast::Association.new(model, id, subresource_name, format, config_assoc_src,
67
+ assoc_model, assoc_config_in, assoc_config_out)
68
+ else
69
+ Toast::ScopedAssociation.new(model, id, subresource_name, scope, params.clone,
70
+ assoc_config_in, assoc_config_out)
71
+ end
70
72
  else
71
73
  raise ResourceNotFound
72
74
  end
@@ -74,6 +76,8 @@ module Toast
74
76
  # set base to be prepended to URIs
75
77
  rsc.base_uri = base_uri
76
78
 
79
+
80
+
77
81
  rsc
78
82
  rescue NameError
79
83
  raise ResourceNotFound
@@ -0,0 +1,23 @@
1
+ module Toast
2
+ class ScopedAssociation < Resource
3
+ # delegeates everything to Toast::Collection, where the model is replaced
4
+ # by the Relation this association creates
5
+
6
+ def initialize(model, id, association_name, scope_name, params,
7
+ config_in, config_out)
8
+
9
+ record = model.find(id)
10
+ assoc_model = record.class
11
+
12
+ @collection = Toast::Collection.new(record.send(association_name),
13
+ scope_name,
14
+ params,
15
+ config_in,
16
+ config_out)
17
+
18
+ end
19
+
20
+ delegate :get, :put, :post, :delete, :base_uri, :base_uri=, :to => :@collection
21
+
22
+ end
23
+ end
data/lib/toast/single.rb CHANGED
@@ -25,10 +25,20 @@ module Toast
25
25
  @params = params
26
26
  @format = params[:format]
27
27
 
28
+ unless @model.respond_to?(subresource_name)
29
+ raise "Toast Error: Cannot find class method '#{@model}.#{subresource_name}', which is configured in 'acts_as_resource > singles'."
30
+ end
28
31
 
29
32
  @record = if @config_out.pass_params_to.include?(subresource_name)
33
+ if @model.method(subresource_name).arity != 1
34
+ raise "Toast Error: Class method '#{@model}.#{subresource_name}' must accept one parameter, as configured by 'acts_as_resource > pass_params_to'."
35
+ end
30
36
  @model.send(subresource_name, @params)
31
37
  else
38
+ if(@model.method(subresource_name).arity < -1 or
39
+ @model.method(subresource_name).arity > 0)
40
+ raise "Toast Error: Class method '#{@model}.#{subresource_name}' must be callable w/o parameters"
41
+ end
32
42
  @model.send(subresource_name)
33
43
  end
34
44
 
@@ -46,7 +56,8 @@ module Toast
46
56
  {
47
57
  :json => @record.represent( @config_out.exposed_attributes,
48
58
  @config_out.exposed_associations,
49
- @base_uri ),
59
+ @base_uri,
60
+ @config_out.media_type),
50
61
  :status => :ok
51
62
  }
52
63
  else
@@ -0,0 +1,3 @@
1
+ module Toast
2
+ VERSION = '0.7.0'
3
+ end
metadata CHANGED
@@ -4,23 +4,49 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
- - 6
7
+ - 7
8
8
  - 0
9
- version: 0.6.0
9
+ version: 0.7.0
10
10
  platform: ruby
11
11
  authors:
12
- - Robert Annies
12
+ - "robokopp (Robert Anni\xC3\xA9s)"
13
13
  autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2012-05-31 00:00:00 +02:00
17
+ date: 2012-07-10 00:00:00 +02:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
- name: blockenspiel
21
+ name: shoulda
22
22
  prerelease: false
23
23
  requirement: &id001 !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 0
29
+ version: "0"
30
+ type: :development
31
+ version_requirements: *id001
32
+ - !ruby/object:Gem::Dependency
33
+ name: rails
34
+ prerelease: false
35
+ requirement: &id002 !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ segments:
40
+ - 3
41
+ - 1
42
+ - 0
43
+ version: 3.1.0
44
+ type: :runtime
45
+ version_requirements: *id002
46
+ - !ruby/object:Gem::Dependency
47
+ name: blockenspiel
48
+ prerelease: false
49
+ requirement: &id003 !ruby/object:Gem::Requirement
24
50
  requirements:
25
51
  - - ~>
26
52
  - !ruby/object:Gem::Version
@@ -30,11 +56,11 @@ dependencies:
30
56
  - 2
31
57
  version: 0.4.2
32
58
  type: :runtime
33
- version_requirements: *id001
59
+ version_requirements: *id003
34
60
  - !ruby/object:Gem::Dependency
35
61
  name: rack-accept-media-types
36
62
  prerelease: false
37
- requirement: &id002 !ruby/object:Gem::Requirement
63
+ requirement: &id004 !ruby/object:Gem::Requirement
38
64
  requirements:
39
65
  - - ~>
40
66
  - !ruby/object:Gem::Version
@@ -43,11 +69,23 @@ dependencies:
43
69
  - 9
44
70
  version: "0.9"
45
71
  type: :runtime
46
- version_requirements: *id002
72
+ version_requirements: *id004
73
+ - !ruby/object:Gem::Dependency
74
+ name: ffaker
75
+ prerelease: false
76
+ requirement: &id005 !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ segments:
81
+ - 0
82
+ version: "0"
83
+ type: :runtime
84
+ version_requirements: *id005
47
85
  description: |-
48
86
  Toast is an extension to Ruby on Rails that lets you expose any
49
- ActiveRecord model as a resource according to the REST paradigm. The
50
- representation format is JSON.
87
+ ActiveRecord model as a resource according to the REST paradigm via a generic controller. The default
88
+ representation format is JSON or can be anything
51
89
  email: robokopp@fernwerk.net
52
90
  executables: []
53
91
 
@@ -59,6 +97,7 @@ files:
59
97
  - app/controller/toast_controller.rb
60
98
  - config/routes.rb
61
99
  - lib/toast.rb
100
+ - lib/toast/version.rb
62
101
  - lib/toast/active_record_extensions.rb
63
102
  - lib/toast/association.rb
64
103
  - lib/toast/collection.rb
@@ -67,6 +106,7 @@ files:
67
106
  - lib/toast/record.rb
68
107
  - lib/toast/resource.rb
69
108
  - lib/toast/single.rb
109
+ - lib/toast/scoped_association.rb
70
110
  - README.md
71
111
  has_rdoc: true
72
112
  homepage: https://github.com/robokopp/toast