daylight 0.9.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +113 -0
- data/app/controllers/daylight_documentation/documentation_controller.rb +27 -0
- data/app/helpers/daylight_documentation/documentation_helper.rb +57 -0
- data/app/views/daylight_documentation/documentation/_header.haml +4 -0
- data/app/views/daylight_documentation/documentation/index.haml +12 -0
- data/app/views/daylight_documentation/documentation/model.haml +114 -0
- data/app/views/layouts/documentation.haml +22 -0
- data/config/routes.rb +8 -0
- data/doc/actions.md +70 -0
- data/doc/benchmarks.md +17 -0
- data/doc/contribute.md +80 -0
- data/doc/develop.md +1205 -0
- data/doc/environment.md +109 -0
- data/doc/example.md +3 -0
- data/doc/framework.md +31 -0
- data/doc/install.md +128 -0
- data/doc/principles.md +42 -0
- data/doc/testing.md +107 -0
- data/doc/usage.md +970 -0
- data/lib/daylight/api.rb +293 -0
- data/lib/daylight/associations.rb +247 -0
- data/lib/daylight/client_reloader.rb +45 -0
- data/lib/daylight/collection.rb +161 -0
- data/lib/daylight/errors.rb +94 -0
- data/lib/daylight/inflections.rb +7 -0
- data/lib/daylight/mock.rb +282 -0
- data/lib/daylight/read_only.rb +88 -0
- data/lib/daylight/refinements.rb +63 -0
- data/lib/daylight/reflection_ext.rb +67 -0
- data/lib/daylight/resource_proxy.rb +226 -0
- data/lib/daylight/version.rb +10 -0
- data/lib/daylight.rb +27 -0
- data/rails/daylight/api_controller.rb +354 -0
- data/rails/daylight/documentation.rb +13 -0
- data/rails/daylight/helpers.rb +32 -0
- data/rails/daylight/params.rb +23 -0
- data/rails/daylight/refiners.rb +186 -0
- data/rails/daylight/server.rb +29 -0
- data/rails/daylight/tasks.rb +37 -0
- data/rails/extensions/array_ext.rb +9 -0
- data/rails/extensions/autosave_association_fix.rb +49 -0
- data/rails/extensions/has_one_serializer_ext.rb +111 -0
- data/rails/extensions/inflections.rb +6 -0
- data/rails/extensions/nested_attributes_ext.rb +94 -0
- data/rails/extensions/read_only_attributes.rb +35 -0
- data/rails/extensions/render_json_meta.rb +99 -0
- data/rails/extensions/route_options.rb +47 -0
- data/rails/extensions/versioned_url_for.rb +22 -0
- data/spec/config/dependencies.rb +2 -0
- data/spec/config/factory_girl.rb +4 -0
- data/spec/config/simplecov_rcov.rb +26 -0
- data/spec/config/test_api.rb +1 -0
- data/spec/controllers/documentation_controller_spec.rb +24 -0
- data/spec/dummy/README.rdoc +28 -0
- data/spec/dummy/Rakefile +6 -0
- data/spec/dummy/app/assets/images/.keep +0 -0
- data/spec/dummy/app/assets/javascripts/application.js +13 -0
- data/spec/dummy/app/assets/stylesheets/application.css +13 -0
- data/spec/dummy/app/controllers/application_controller.rb +5 -0
- data/spec/dummy/app/controllers/concerns/.keep +0 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/mailers/.keep +0 -0
- data/spec/dummy/app/models/.keep +0 -0
- data/spec/dummy/app/models/concerns/.keep +0 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/bin/bundle +3 -0
- data/spec/dummy/bin/rails +4 -0
- data/spec/dummy/bin/rake +4 -0
- data/spec/dummy/config/application.rb +24 -0
- data/spec/dummy/config/boot.rb +5 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +29 -0
- data/spec/dummy/config/environments/production.rb +80 -0
- data/spec/dummy/config/environments/test.rb +36 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/daylight.rb +1 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/dummy/config/initializers/inflections.rb +16 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/secret_token.rb +12 -0
- data/spec/dummy/config/initializers/session_store.rb +3 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +23 -0
- data/spec/dummy/config/routes.rb +59 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/lib/assets/.keep +0 -0
- data/spec/dummy/log/.keep +0 -0
- data/spec/dummy/public/404.html +58 -0
- data/spec/dummy/public/422.html +58 -0
- data/spec/dummy/public/500.html +57 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/helpers/documentation_helper_spec.rb +82 -0
- data/spec/lib/daylight/api_spec.rb +178 -0
- data/spec/lib/daylight/associations_spec.rb +325 -0
- data/spec/lib/daylight/collection_spec.rb +235 -0
- data/spec/lib/daylight/errors_spec.rb +111 -0
- data/spec/lib/daylight/mock_spec.rb +144 -0
- data/spec/lib/daylight/read_only_spec.rb +118 -0
- data/spec/lib/daylight/refinements_spec.rb +80 -0
- data/spec/lib/daylight/reflection_ext_spec.rb +50 -0
- data/spec/lib/daylight/resource_proxy_spec.rb +325 -0
- data/spec/rails/daylight/api_controller_spec.rb +421 -0
- data/spec/rails/daylight/helpers_spec.rb +41 -0
- data/spec/rails/daylight/params_spec.rb +45 -0
- data/spec/rails/daylight/refiners_spec.rb +178 -0
- data/spec/rails/extensions/array_ext_spec.rb +51 -0
- data/spec/rails/extensions/has_one_serializer_ext_spec.rb +135 -0
- data/spec/rails/extensions/nested_attributes_ext_spec.rb +177 -0
- data/spec/rails/extensions/render_json_meta_spec.rb +140 -0
- data/spec/rails/extensions/route_options_spec.rb +309 -0
- data/spec/rails/extensions/versioned_url_for_spec.rb +46 -0
- data/spec/spec_helper.rb +43 -0
- data/spec/support/migration_helper.rb +40 -0
- metadata +422 -0
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'active_resource/reflection'
|
2
|
+
|
3
|
+
##
|
4
|
+
# Extension to use the API namespace and version modules to lookup classes for
|
5
|
+
# a reflection. The benefit is to be able to define an association wihtout
|
6
|
+
# the module name or using the :class_name option.
|
7
|
+
#
|
8
|
+
# Without the extension, we have to specify the `:class_name`:
|
9
|
+
#
|
10
|
+
# class API::V1::Post < Daylight::API
|
11
|
+
# has_many :comments, class_name: 'api/v1/comment'
|
12
|
+
# end
|
13
|
+
#
|
14
|
+
# With the extension, it will be determined using the namespace and version modules
|
15
|
+
#
|
16
|
+
# class API::V1::Post < Daylight::API
|
17
|
+
# belongs_to :blog
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# API::V1::Post.find(1).blog #=> #<API::V1::Blog:0x007ffa8a43f1e8 ...>
|
21
|
+
#
|
22
|
+
# The `:class_name` option still can be specified for alternate behavior
|
23
|
+
#
|
24
|
+
# class API::V1::Post < Daylight::API
|
25
|
+
# belongs_to :author, class_name: 'api/v1/user', foreign_key: 'created_by'
|
26
|
+
# end
|
27
|
+
|
28
|
+
module Daylight::ReflectionExt
|
29
|
+
extend ActiveSupport::Concern
|
30
|
+
|
31
|
+
included do
|
32
|
+
##
|
33
|
+
# Determines and tests for the name with namespace and version.
|
34
|
+
#
|
35
|
+
# Falls back to the name of the association which was the original behavior
|
36
|
+
# of `AssociationReflection`.
|
37
|
+
#
|
38
|
+
# See
|
39
|
+
# ActiveResource::Reflection::AssociationReflection
|
40
|
+
|
41
|
+
def expanded_name
|
42
|
+
@expanded_name = begin
|
43
|
+
candidate_name = [Daylight::API.namespace, Daylight::API.version, name.to_s.classify].join("::")
|
44
|
+
candidate_name.classify.constantize # test for the name, raise if non-existant
|
45
|
+
candidate_name.underscore
|
46
|
+
rescue
|
47
|
+
name.to_s # fallback to using the original functionality
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
##
|
53
|
+
# Uses the expanded or default name to derive the class name. Changes
|
54
|
+
# original `AssociationReflection` functionality.
|
55
|
+
#
|
56
|
+
# See
|
57
|
+
# ActiveResource::Reflection::AssociationReflection.derive_class_name
|
58
|
+
|
59
|
+
def derive_class_name
|
60
|
+
return (options[:class_name] ? options[:class_name].to_s : expanded_name).classify
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
ActiveResource::Reflection::AssociationReflection.class_eval do
|
66
|
+
include Daylight::ReflectionExt
|
67
|
+
end
|
@@ -0,0 +1,226 @@
|
|
1
|
+
##
|
2
|
+
# Proxies requests to ActiveResource once the data has been accessed.
|
3
|
+
# Allows chaining of scope calls ala ActiveRecord
|
4
|
+
class Daylight::ResourceProxy
|
5
|
+
include Enumerable
|
6
|
+
|
7
|
+
delegate :to_xml, :to_yaml, :length, :each, :to_ary, :size, :last, :[], :==, to: :to_a
|
8
|
+
delegate :first_or_initialize, :first_or_create, to: :records
|
9
|
+
delegate :resource_class, to: :class
|
10
|
+
|
11
|
+
attr_reader :association_name, :association_resource
|
12
|
+
|
13
|
+
# turn off constructor, only use factory methods
|
14
|
+
private_class_method :new
|
15
|
+
|
16
|
+
def initialize association={}
|
17
|
+
@current_params = {}
|
18
|
+
@association_name, @association_resource = association.first
|
19
|
+
end
|
20
|
+
|
21
|
+
##
|
22
|
+
# Delegates appending to the association resource when available
|
23
|
+
|
24
|
+
def << value
|
25
|
+
if association_resource
|
26
|
+
association_resource.send("#{association_name}=", records.elements << value)
|
27
|
+
else
|
28
|
+
raise NoMethodError, "undefined method `<<' for #{self}"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
##
|
33
|
+
# Sets `from` URL on a request
|
34
|
+
def from from
|
35
|
+
@from = from
|
36
|
+
self
|
37
|
+
end
|
38
|
+
|
39
|
+
##
|
40
|
+
# Loads records from server based on current paremeters and from URL
|
41
|
+
def load
|
42
|
+
resource_class.find(:all, params: to_params, from: @from)
|
43
|
+
end
|
44
|
+
|
45
|
+
##
|
46
|
+
# Returns a copy of the current parameters used to fetch records
|
47
|
+
def to_params
|
48
|
+
current_params.dup
|
49
|
+
end
|
50
|
+
|
51
|
+
##
|
52
|
+
# Returns the records, requests them from server if not fetched
|
53
|
+
def records
|
54
|
+
@records ||= load
|
55
|
+
end
|
56
|
+
|
57
|
+
##
|
58
|
+
# Returns the records, forces fetch from server
|
59
|
+
def reload
|
60
|
+
@records = load
|
61
|
+
end
|
62
|
+
|
63
|
+
##
|
64
|
+
# Converts records to an Array
|
65
|
+
def to_a
|
66
|
+
records.to_a
|
67
|
+
end
|
68
|
+
|
69
|
+
##
|
70
|
+
# Adds scopes to the current parameters
|
71
|
+
def append_scope scope
|
72
|
+
spawn.tap do |proxy|
|
73
|
+
proxy.current_params[:scopes] ||= []
|
74
|
+
proxy.current_params[:scopes] << scope
|
75
|
+
proxy.current_params[:scopes].uniq!
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
##
|
80
|
+
# Merges conditions to the current parameters
|
81
|
+
def where conditions
|
82
|
+
spawn.tap do |proxy|
|
83
|
+
proxy.current_params[:filters] ||= {}
|
84
|
+
proxy.current_params[:filters].merge! conditions
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
##
|
89
|
+
# Sets limit in the current parameters
|
90
|
+
def limit value
|
91
|
+
spawn.tap do |proxy|
|
92
|
+
proxy.current_params[:limit] = value
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
##
|
97
|
+
# Sets order in the current parameters
|
98
|
+
def order value
|
99
|
+
spawn.tap do |proxy|
|
100
|
+
proxy.current_params[:order] = value
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
##
|
105
|
+
# Sets offset in the current parameters
|
106
|
+
def offset value
|
107
|
+
spawn.tap do |proxy|
|
108
|
+
proxy.current_params[:offset] = value
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
##
|
113
|
+
# Merges conditions to the current parameters, and fetches the first result.
|
114
|
+
# Immediately issues the request to the API.
|
115
|
+
|
116
|
+
def find_by conditions
|
117
|
+
where(conditions).limit(1).first
|
118
|
+
end
|
119
|
+
|
120
|
+
##
|
121
|
+
# Sets the limit to the current parameters, and fetches the first result.
|
122
|
+
# Immediately issues the request to the API.
|
123
|
+
|
124
|
+
def first
|
125
|
+
limit(1).to_a.first
|
126
|
+
end
|
127
|
+
|
128
|
+
##
|
129
|
+
# Special inspect that shows the fetched results (up to 10 fo them) and the
|
130
|
+
# current params to fetch those results.
|
131
|
+
#
|
132
|
+
# Immediately issues the request to the API.
|
133
|
+
|
134
|
+
def inspect
|
135
|
+
records = to_a.take(11)
|
136
|
+
records[10] = '...' if entries.size == 11
|
137
|
+
|
138
|
+
"#<#{self.class.name} #{records} @current_params=#{current_params}>"
|
139
|
+
end
|
140
|
+
|
141
|
+
class << self
|
142
|
+
# Each ResourceProxy will have thier own resource
|
143
|
+
attr_accessor :resource_class
|
144
|
+
|
145
|
+
##
|
146
|
+
# Factory method to generate a child class for ResourceProxy with the
|
147
|
+
# required resource class.
|
148
|
+
#
|
149
|
+
# proxy = ResourceProxy[User] #=> User::ResourceProxy
|
150
|
+
#
|
151
|
+
# Onece a child class has been created, it can be use it to create
|
152
|
+
# instances:
|
153
|
+
#
|
154
|
+
# ResourceProxy[User].new
|
155
|
+
|
156
|
+
def [] resource_class
|
157
|
+
if resource_class.const_defined?(:ResourceProxy)
|
158
|
+
return resource_class.const_get(:ResourceProxy)
|
159
|
+
end
|
160
|
+
|
161
|
+
Class.new(Daylight::ResourceProxy) do
|
162
|
+
# Allow instances to be created
|
163
|
+
public_class_method :new
|
164
|
+
|
165
|
+
# Set our resource
|
166
|
+
self.resource_class = resource_class
|
167
|
+
|
168
|
+
# Set our ResourceProxy constant
|
169
|
+
resource_class.const_set(:ResourceProxy, self)
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
##
|
174
|
+
# Define a name for the class
|
175
|
+
def name
|
176
|
+
"#{resource_class}::ResourceProxy"
|
177
|
+
end
|
178
|
+
|
179
|
+
##
|
180
|
+
# Use the class name as the inspect
|
181
|
+
alias_method :inspect, :name
|
182
|
+
end
|
183
|
+
|
184
|
+
##
|
185
|
+
# Will attempt to fulfill the method if it exists on the resource or if it
|
186
|
+
# exists on an Array. Defines or delegates the method on for subsequent
|
187
|
+
# execution.
|
188
|
+
|
189
|
+
def method_missing(method_name, *args, &block)
|
190
|
+
if resource_class.respond_to?(method_name)
|
191
|
+
self.class.send(:define_method, method_name) do |*method_args, &method_block|
|
192
|
+
resource_class.send(method_name, *method_args, &method_block)
|
193
|
+
end
|
194
|
+
resource_class.send(method_name, *args, &block)
|
195
|
+
elsif Array.method_defined?(method_name)
|
196
|
+
self.class.delegate method_name, :to => :to_a
|
197
|
+
to_a.send(method_name, *args, &block)
|
198
|
+
else
|
199
|
+
super
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
protected
|
204
|
+
attr_accessor :current_params
|
205
|
+
|
206
|
+
##
|
207
|
+
# Clone current ResourceProxy and with `current_params` to keep its query
|
208
|
+
# context
|
209
|
+
#
|
210
|
+
# See
|
211
|
+
# reset
|
212
|
+
|
213
|
+
def spawn
|
214
|
+
clone.reset(current_params)
|
215
|
+
end
|
216
|
+
|
217
|
+
##
|
218
|
+
# Resets a ResourceProxy marked to refetch results based on blank or
|
219
|
+
# supplied `current_params`
|
220
|
+
|
221
|
+
def reset old_params={}
|
222
|
+
@current_params = old_params.deep_dup
|
223
|
+
@records = nil
|
224
|
+
self
|
225
|
+
end
|
226
|
+
end
|
data/lib/daylight.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
$:.unshift File.expand_path('../../rails', __FILE__)
|
2
|
+
|
3
|
+
require 'active_support/core_ext'
|
4
|
+
require 'active_resource'
|
5
|
+
|
6
|
+
##
|
7
|
+
# Include into API client to enable Daylight::API based queries
|
8
|
+
|
9
|
+
module Daylight
|
10
|
+
extend ActiveSupport::Autoload
|
11
|
+
|
12
|
+
eager_autoload do
|
13
|
+
autoload :Version
|
14
|
+
autoload :Associations
|
15
|
+
autoload :Collection
|
16
|
+
autoload :Errors
|
17
|
+
autoload :Inflections
|
18
|
+
autoload :Refinements
|
19
|
+
autoload :ReadOnly
|
20
|
+
autoload :ResourceProxy
|
21
|
+
autoload :ReflectionExt
|
22
|
+
autoload :API
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# run eager load
|
27
|
+
Daylight.eager_load!
|
@@ -0,0 +1,354 @@
|
|
1
|
+
##
|
2
|
+
# Common conntroller built on top of `ApplicationController` that assists with
|
3
|
+
# setting up standard, conventional REST and Daylight supported actions.
|
4
|
+
#
|
5
|
+
# Have your API Controllers subclass from APIController:
|
6
|
+
#
|
7
|
+
# class ExampleController < APIController
|
8
|
+
# end
|
9
|
+
#
|
10
|
+
# You must "turn on" common actions to allow for functionality. All common
|
11
|
+
# actions are turned off by default so that what is exposed is
|
12
|
+
# determiend by the API devloper. For example, to turn on `index` action:
|
13
|
+
#
|
14
|
+
# class ExampleController < APIController
|
15
|
+
# handles :index
|
16
|
+
# end
|
17
|
+
#
|
18
|
+
# The common actions provided by APIController are: `:index`, `:create`,
|
19
|
+
# `:show`, `:update`, `:destroy`, `:associated`, and `:remoted`.
|
20
|
+
#
|
21
|
+
# The method implementations are simply methods in a superclass and can be
|
22
|
+
# overwritten or called through `super`:
|
23
|
+
#
|
24
|
+
# class ExampleController < APIController
|
25
|
+
# handles :index
|
26
|
+
#
|
27
|
+
# def index
|
28
|
+
# @title = 'My Title'
|
29
|
+
# super
|
30
|
+
# end
|
31
|
+
# end
|
32
|
+
#
|
33
|
+
# The model and instance variable for these actions are based on the
|
34
|
+
# controller name. If you need to customize these, you can change them:
|
35
|
+
#
|
36
|
+
# class ExampleController < APIController
|
37
|
+
# self.model_name = :news
|
38
|
+
# self.record_name = :post
|
39
|
+
#
|
40
|
+
# handles :index
|
41
|
+
# end
|
42
|
+
#
|
43
|
+
# Continue to use `ApplicationController` for shared methods.
|
44
|
+
#
|
45
|
+
# See:
|
46
|
+
# ApplicationController
|
47
|
+
|
48
|
+
class Daylight::APIController < ApplicationController
|
49
|
+
include Daylight::Helpers
|
50
|
+
include VersionedUrlFor
|
51
|
+
|
52
|
+
API_ACTIONS = [:index, :create, :show, :update, :destroy, :associated, :remoted].freeze
|
53
|
+
class_attribute :record_name, :collection_name, :model_name
|
54
|
+
|
55
|
+
alias_method :set_record_name, :record_name= #:nodoc:
|
56
|
+
alias_method :set_collection_name, :collection_name= #:nodoc:
|
57
|
+
alias_method :set_model_name, :model_name= #:nodoc:
|
58
|
+
|
59
|
+
##
|
60
|
+
# Ensure messaging when sending unknown attributes or improper SQL
|
61
|
+
rescue_from ArgumentError,
|
62
|
+
ActiveRecord::UnknownAttributeError,
|
63
|
+
ActiveRecord::StatementInvalid do |e|
|
64
|
+
|
65
|
+
render json: { errors: e.message }, status: :bad_request
|
66
|
+
end
|
67
|
+
|
68
|
+
##
|
69
|
+
# Ensure messaging when there are validation errors on save and update
|
70
|
+
rescue_from ActiveRecord::RecordInvalid do |e|
|
71
|
+
render json: { errors: e.record.errors }, status: :unprocessable_entity
|
72
|
+
end
|
73
|
+
|
74
|
+
##
|
75
|
+
# Ensure messaging when there unpermitted attributes on save and update
|
76
|
+
rescue_from ActionController::UnpermittedParameters do |e|
|
77
|
+
errors = {}
|
78
|
+
e.params.each { |key| errors[key] = ['unpermitted parameter'] }
|
79
|
+
render json: { errors: errors }, status: :unprocessable_entity
|
80
|
+
end
|
81
|
+
|
82
|
+
##
|
83
|
+
# Ensure messaging when attributes have not been permitted on the controller
|
84
|
+
rescue_from ActiveModel::ForbiddenAttributesError do |e|
|
85
|
+
render json: { errors: 'parameters have not been permitted on this action' }, status: :bad_request
|
86
|
+
end
|
87
|
+
|
88
|
+
|
89
|
+
class << self
|
90
|
+
protected
|
91
|
+
##
|
92
|
+
# Turns on common actions based on subclass needs (sets them as public methods).
|
93
|
+
# Uses whitelist of allowed actions to be handled.
|
94
|
+
#
|
95
|
+
# See:
|
96
|
+
# API_ACTIONS
|
97
|
+
#--
|
98
|
+
# `public` is called in context of the subclass
|
99
|
+
def handles *actions
|
100
|
+
actions = API_ACTIONS.dup if actions.any? {|a| a == :all }
|
101
|
+
|
102
|
+
whitelisted = actions.map(&:to_sym) & API_ACTIONS
|
103
|
+
|
104
|
+
if (unhandled = actions - whitelisted).present?
|
105
|
+
logger.warn "Daylight::APIController isn't handling unwhitelisted actions"
|
106
|
+
logger.warn "\tspecified in #{self.name}#handles: #{unhandled.join(',')}"
|
107
|
+
end
|
108
|
+
|
109
|
+
public(*whitelisted) if whitelisted.present?
|
110
|
+
end
|
111
|
+
|
112
|
+
##
|
113
|
+
# Retrieves conventional key for a model name used in params
|
114
|
+
def model_key
|
115
|
+
model_name.to_s.singularize.to_sym
|
116
|
+
end
|
117
|
+
|
118
|
+
##
|
119
|
+
# Retieves `const` for ActiveRecord model as defined by `model_name`
|
120
|
+
def model
|
121
|
+
model_name.to_s.classify.constantize
|
122
|
+
end
|
123
|
+
|
124
|
+
##
|
125
|
+
# Delegates to `model#primary_key`
|
126
|
+
# Not using delegate as model may change via `model_name` configuration
|
127
|
+
def primary_key
|
128
|
+
model.primary_key
|
129
|
+
end
|
130
|
+
|
131
|
+
##
|
132
|
+
# Sets the default `model_name` and `record_name` by default.
|
133
|
+
# By default, they are based on the value determined by `controller_name`
|
134
|
+
#
|
135
|
+
# See:
|
136
|
+
# ActionController::Base.controller_name
|
137
|
+
def inherited api
|
138
|
+
name = api.controller_name.singularize
|
139
|
+
|
140
|
+
api.model_name = name
|
141
|
+
api.record_name = name
|
142
|
+
api.collection_name = 'collection'
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
protected
|
147
|
+
##
|
148
|
+
# Retrieves the value for the `record_name` instance variable
|
149
|
+
def record
|
150
|
+
instance_variable_get("@#{record_name}")
|
151
|
+
end
|
152
|
+
|
153
|
+
##
|
154
|
+
# Sets the value for the `record_name` instance variable
|
155
|
+
def record= value
|
156
|
+
instance_variable_set("@#{record_name}", value)
|
157
|
+
end
|
158
|
+
|
159
|
+
##
|
160
|
+
# Retrieves the value for the `record_name` instance variable
|
161
|
+
def collection
|
162
|
+
instance_variable_get("@#{collection_name}")
|
163
|
+
end
|
164
|
+
|
165
|
+
##
|
166
|
+
# Sets the value for the `record_name` instance variable
|
167
|
+
def collection= value
|
168
|
+
instance_variable_set("@#{collection_name}", value)
|
169
|
+
end
|
170
|
+
|
171
|
+
##
|
172
|
+
# Instance-level delegate of the `model` method
|
173
|
+
#
|
174
|
+
# See:
|
175
|
+
# #model
|
176
|
+
def model
|
177
|
+
self.class.send(:model)
|
178
|
+
end
|
179
|
+
|
180
|
+
##
|
181
|
+
# Instance-level delegate of the `model_key` method
|
182
|
+
#
|
183
|
+
# See:
|
184
|
+
# #model_key
|
185
|
+
def model_key
|
186
|
+
self.class.send(:model_key)
|
187
|
+
end
|
188
|
+
|
189
|
+
##
|
190
|
+
# Retrieves the strong parameters for a model based on the `model_key` name.
|
191
|
+
# Ex. post_params
|
192
|
+
#
|
193
|
+
# If strong parameters are not defined, it will use the `model_key` to
|
194
|
+
# dereference the raw params.
|
195
|
+
# Ex. params[:post]
|
196
|
+
def model_params
|
197
|
+
model_params_name = "#{model_key}_params"
|
198
|
+
respond_to?(model_params_name, true) ? send(model_params_name) : params[model_key]
|
199
|
+
end
|
200
|
+
|
201
|
+
##
|
202
|
+
# Instance-level delegate of the `primary_key` method
|
203
|
+
#
|
204
|
+
# See:
|
205
|
+
# #primary_key
|
206
|
+
def primary_key
|
207
|
+
self.class.send(:primary_key)
|
208
|
+
end
|
209
|
+
private
|
210
|
+
#
|
211
|
+
# The common actions for Daylight::APIController
|
212
|
+
#
|
213
|
+
|
214
|
+
##
|
215
|
+
# Retrieves the collection for the records for `model` with any refinements
|
216
|
+
# in the params passed to `refine_by`. Accessed via:
|
217
|
+
#
|
218
|
+
# GET /posts.json
|
219
|
+
#
|
220
|
+
# Subclass implementation:
|
221
|
+
#
|
222
|
+
# def index
|
223
|
+
# render json: Post.refine_by(params)
|
224
|
+
# end
|
225
|
+
#
|
226
|
+
# See:
|
227
|
+
# Daylight::Refiners.refine_by
|
228
|
+
def index
|
229
|
+
render json: self.collection = model.refine_by(params)
|
230
|
+
end
|
231
|
+
|
232
|
+
##
|
233
|
+
# Creates a record for the `model` with the attributes supplied in params.
|
234
|
+
# Accessed via:
|
235
|
+
#
|
236
|
+
# POST /posts.json
|
237
|
+
#
|
238
|
+
# Subclass implementation:
|
239
|
+
#
|
240
|
+
# def create
|
241
|
+
# @post = Post.new(params[:post])
|
242
|
+
# @post.save!
|
243
|
+
#
|
244
|
+
# render json: @post, status: :created, location: @post
|
245
|
+
# end
|
246
|
+
def create
|
247
|
+
self.record = model.new(model_params)
|
248
|
+
record.save!
|
249
|
+
|
250
|
+
render json: record, status: :created, location: record
|
251
|
+
end
|
252
|
+
|
253
|
+
##
|
254
|
+
# Retrieves a record for the `model` with the `id` supplied in params.
|
255
|
+
# If the primary_key is configured to something besides `id` it will
|
256
|
+
# use that as a key.
|
257
|
+
#
|
258
|
+
# Accessed via:
|
259
|
+
#
|
260
|
+
# GET /posts/1.json
|
261
|
+
#
|
262
|
+
# Subclass implementation:
|
263
|
+
#
|
264
|
+
# def show
|
265
|
+
# render json: Post.find(params[Post.primary_key])
|
266
|
+
# end
|
267
|
+
def show
|
268
|
+
render json: self.record = model.find(params[primary_key])
|
269
|
+
end
|
270
|
+
|
271
|
+
##
|
272
|
+
# Updates a record for the `model` with the `id` supplied in params.
|
273
|
+
# If the primary_key is configured to something besides `id` it will
|
274
|
+
# use that as a key.
|
275
|
+
#
|
276
|
+
# Accessed via:
|
277
|
+
#
|
278
|
+
# PATCH/PUT /posts/1.json
|
279
|
+
#
|
280
|
+
# Subclass implementation:
|
281
|
+
#
|
282
|
+
# def update
|
283
|
+
# Post.find(params[Post.primary_key]).update!(params[:post])
|
284
|
+
#
|
285
|
+
# head :no_content
|
286
|
+
# end
|
287
|
+
def update
|
288
|
+
(self.record = model.find(params[primary_key])).update!(model_params)
|
289
|
+
|
290
|
+
head :no_content
|
291
|
+
end
|
292
|
+
|
293
|
+
##
|
294
|
+
# Destroys a record for the `model` with the `id` supplied in params.
|
295
|
+
# If the primary_key is configured to something besides `id` it will
|
296
|
+
# use that as a key.
|
297
|
+
#
|
298
|
+
# Accessed via:
|
299
|
+
#
|
300
|
+
# DELETE /posts/1.json
|
301
|
+
#
|
302
|
+
# Subclass implementation:
|
303
|
+
#
|
304
|
+
# def destroy
|
305
|
+
# Post.find(params[Post.primary_key]).destroy
|
306
|
+
#
|
307
|
+
# head :no_content
|
308
|
+
# end
|
309
|
+
def destroy
|
310
|
+
(self.record = model.find(params[primary_key])).destroy
|
311
|
+
|
312
|
+
head :no_content
|
313
|
+
end
|
314
|
+
|
315
|
+
##
|
316
|
+
# Retrieves the collection for the associated records for a `model` with
|
317
|
+
# any refinements in the params passed to `associated`. Accessed via:
|
318
|
+
#
|
319
|
+
# GET /posts/1/comments.json
|
320
|
+
#
|
321
|
+
# Subclass implementation:
|
322
|
+
#
|
323
|
+
# def associated
|
324
|
+
# render json: Post.associated(params), root: associated_params
|
325
|
+
# end
|
326
|
+
#
|
327
|
+
# See:
|
328
|
+
# Daylight::Refiners.associated
|
329
|
+
# Daylight::Helpers.associated_params
|
330
|
+
# RouteOptions
|
331
|
+
def associated
|
332
|
+
render json: self.collection = model.associated(params), root: associated_params
|
333
|
+
end
|
334
|
+
|
335
|
+
##
|
336
|
+
# Retrieves the collection returned by the `remoted` method with
|
337
|
+
# any refinements in the params passed to `remoted`. Accessed via:
|
338
|
+
#
|
339
|
+
# GET /posts/1/all_authorized_users.json
|
340
|
+
#
|
341
|
+
# Subclass implementation:
|
342
|
+
#
|
343
|
+
# def remoted
|
344
|
+
# render json: Post.remoted(params), root: remoted_params
|
345
|
+
# end
|
346
|
+
#
|
347
|
+
# See:
|
348
|
+
# Daylight::Refiners.remoted
|
349
|
+
# Daylight::Helpers.remoted_params
|
350
|
+
# RouteOptions
|
351
|
+
def remoted
|
352
|
+
render json: self.collection = model.remoted(params), root: remoted_params
|
353
|
+
end
|
354
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'haml'
|
2
|
+
require 'actionpack/page_caching'
|
3
|
+
|
4
|
+
module DaylightDocumentation
|
5
|
+
end
|
6
|
+
|
7
|
+
##
|
8
|
+
# Rails::Engine to add Documentation features to a Daylight::Server
|
9
|
+
module Daylight
|
10
|
+
class Documentation < ::Rails::Engine
|
11
|
+
isolate_namespace DaylightDocumentation
|
12
|
+
end
|
13
|
+
end
|