rest_framework 0.9.5 → 0.9.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +1 -1
  3. data/README.md +130 -0
  4. data/VERSION +1 -1
  5. data/app/views/layouts/rest_framework.html.erb +9 -183
  6. data/app/views/rest_framework/_breadcrumbs.html.erb +27 -0
  7. data/app/views/rest_framework/_head.html.erb +347 -190
  8. data/app/views/rest_framework/_header.html.erb +15 -0
  9. data/app/views/rest_framework/_heading.html.erb +10 -0
  10. data/app/views/rest_framework/_payloads.html.erb +36 -0
  11. data/app/views/rest_framework/_request_metadata.html.erb +16 -0
  12. data/app/views/rest_framework/_routes_and_forms.html.erb +52 -0
  13. data/app/views/rest_framework/head/_external.html.erb +7 -2
  14. data/app/views/rest_framework/header/_mode.html.erb +14 -0
  15. data/app/views/rest_framework/heading/_actions.html.erb +9 -0
  16. data/app/views/rest_framework/{_routes.html.erb → routes_and_forms/_routes.html.erb} +2 -2
  17. data/lib/rest_framework/controller_mixins/base.rb +11 -12
  18. data/lib/rest_framework/engine.rb +5 -3
  19. data/lib/rest_framework/filters/ransack.rb +6 -6
  20. data/lib/rest_framework/version.rb +3 -8
  21. data/lib/rest_framework.rb +11 -2
  22. data/vendor/assets/javascripts/rest_framework/external.min.js +1256 -0
  23. data/vendor/assets/stylesheets/rest_framework/{bootstrap-icons.min.css → external.min.css} +415 -0
  24. data/vendor/assets/stylesheets/rest_framework/highlight-a11y-dark.min.css +1 -1
  25. data/vendor/assets/stylesheets/rest_framework/highlight-a11y-light.min.css +1 -1
  26. metadata +16 -33
  27. data/README.md +0 -1
  28. data/app/views/rest_framework/head/_shared.html +0 -164
  29. data/docs/CNAME +0 -1
  30. data/docs/Gemfile +0 -5
  31. data/docs/Gemfile.lock +0 -264
  32. data/docs/_config.yml +0 -19
  33. data/docs/_guide/1_routers.md +0 -110
  34. data/docs/_guide/2_controllers.md +0 -342
  35. data/docs/_guide/3_serializers.md +0 -60
  36. data/docs/_guide/4_filtering_and_ordering.md +0 -41
  37. data/docs/_guide/5_pagination.md +0 -21
  38. data/docs/_includes/anchor_headings.html +0 -144
  39. data/docs/_includes/external.html +0 -9
  40. data/docs/_includes/head.html +0 -155
  41. data/docs/_includes/header.html +0 -58
  42. data/docs/_includes/shared.html +0 -164
  43. data/docs/_layouts/default.html +0 -11
  44. data/docs/assets/images/favicon.ico +0 -0
  45. data/docs/index.md +0 -133
  46. data/vendor/assets/javascripts/rest_framework/bootstrap.min.js +0 -6
  47. data/vendor/assets/javascripts/rest_framework/highlight-json.min.js +0 -7
  48. data/vendor/assets/javascripts/rest_framework/highlight-xml.min.js +0 -29
  49. data/vendor/assets/javascripts/rest_framework/highlight.min.js +0 -1202
  50. data/vendor/assets/javascripts/rest_framework/neatjson.min.js +0 -7
  51. data/vendor/assets/javascripts/rest_framework/trix.min.js +0 -6
  52. data/vendor/assets/stylesheets/rest_framework/bootstrap.min.css +0 -5
  53. data/vendor/assets/stylesheets/rest_framework/trix.min.css +0 -410
  54. /data/app/views/rest_framework/{_html_form.html.erb → routes_and_forms/_html_form.html.erb} +0 -0
  55. /data/app/views/rest_framework/{_raw_form.html.erb → routes_and_forms/_raw_form.html.erb} +0 -0
  56. /data/app/views/rest_framework/{_route.html.erb → routes_and_forms/routes/_route.html.erb} +0 -0
@@ -0,0 +1,52 @@
1
+ <%
2
+ @is_model_controller = controller.class.included_modules.include?(RESTFramework::ModelControllerMixin)
3
+ %>
4
+ <div class="row">
5
+ <div>
6
+ <ul class="nav nav-tabs">
7
+ <li class="nav-item">
8
+ <a class="nav-link active" href="#tab-routes" data-bs-toggle="tab" role="tab">
9
+ Routes
10
+ </a>
11
+ </li>
12
+ <% @_rrf_form_routes_raw = @route_groups.values[0].select { |r|
13
+ r[:matches_params] && (
14
+ r[:verb].in?(["POST", "PUT", "PATCH"]) ||
15
+ (r[:verb] == "DELETE" && r[:action] == "destroy_all")
16
+ )
17
+ } %>
18
+ <% @_rrf_form_routes_html = @route_groups.values[0].select { |r|
19
+ r[:matches_params] && r[:verb].in?(["POST", "PUT", "PATCH"])
20
+ } %>
21
+ <% if @_rrf_form_routes_raw.present? %>
22
+ <li class="nav-item">
23
+ <a class="nav-link" href="#tabRawForm" data-bs-toggle="tab" role="tab">
24
+ Raw Form
25
+ </a>
26
+ </li>
27
+ <% end %>
28
+ <% if @_rrf_form_routes_html.present? && @is_model_controller %>
29
+ <li class="nav-item">
30
+ <a class="nav-link" href="#tabHtmlForm" data-bs-toggle="tab" role="tab">
31
+ HTML Form
32
+ </a>
33
+ </li>
34
+ <% end %>
35
+ </ul>
36
+ </div>
37
+ <div class="tab-content pt-2">
38
+ <div class="tab-pane fade show active" id="tab-routes" role="tabpanel">
39
+ <%= render partial: "rest_framework/routes_and_forms/routes" %>
40
+ </div>
41
+ <% if @_rrf_form_routes_raw.present? %>
42
+ <div class="tab-pane fade" id="tabRawForm" role="tabpanel">
43
+ <%= render partial: "rest_framework/routes_and_forms/raw_form" %>
44
+ </div>
45
+ <% end %>
46
+ <% if @_rrf_form_routes_html.present? && @is_model_controller %>
47
+ <div class="tab-pane fade" id="tabHtmlForm" role="tabpanel">
48
+ <%= render partial: "rest_framework/routes_and_forms/html_form" %>
49
+ </div>
50
+ <% end %>
51
+ </div>
52
+ </div>
@@ -1,9 +1,14 @@
1
1
  <% if RESTFramework.config.use_vendored_assets %>
2
- <% RESTFramework::EXTERNAL_ASSETS.each do |name, cfg| %>
2
+ <%= javascript_include_tag RESTFramework::EXTERNAL_JS_NAME, defer: true %>
3
+ <%= stylesheet_link_tag RESTFramework::EXTERNAL_CSS_NAME %>
4
+
5
+ <% RESTFramework::EXTERNAL_UNSUMMARIZED_ASSETS.each do |name, cfg| %>
3
6
  <% if cfg[:place] == "javascripts" %>
4
7
  <%= javascript_include_tag "rest_framework/#{name}", defer: true, **cfg[:extra_tag_attrs] %>
5
- <% else %>
8
+ <% elsif cfg[:place] == "stylesheets" %>
6
9
  <%= stylesheet_link_tag "rest_framework/#{name}", **cfg[:extra_tag_attrs] %>
10
+ <% else %>
11
+ <% raise "Unknown asset place." %>
7
12
  <% end %>
8
13
  <% end %>
9
14
  <% else %>
@@ -0,0 +1,14 @@
1
+ <div class="dropdown float-end" id="rrfModeComponent">
2
+ <button class="btn btn-dark dropdown-toggle rounded-0 bg-black" style="border-color: black" data-bs-toggle="dropdown"></button>
3
+ <div class="rrf-mode dropdown-menu dropdown-menu-end py-0 rounded-0" style="font-size: .8em; min-width: 0">
4
+ <button class="dropdown-item text-end" data-rrf-mode-value="system">
5
+ System<i class="bi bi-circle-half ms-2"></i>
6
+ </button>
7
+ <button class="dropdown-item text-end" data-rrf-mode-value="light">
8
+ Light<i class="bi bi-sun-fill ms-2"></i>
9
+ </button>
10
+ <button class="dropdown-item text-end" data-rrf-mode-value="dark">
11
+ Dark<i class="bi bi-moon-stars-fill ms-2"></i>
12
+ </button>
13
+ </div>
14
+ </div>
@@ -0,0 +1,9 @@
1
+ <div style="float: right">
2
+ <% if @route_groups.values[0].any? { |r| r[:matches_path] && r[:verb] == "DELETE" && r[:action] == "destroy" } %>
3
+ <button type="button" class="btn btn-danger" onclick="rrfDelete(this)">DELETE</button>
4
+ <% end %>
5
+ <% if @route_groups.values[0].any? { |r| r[:matches_path] && r[:verb] == "OPTIONS" } %>
6
+ <button type="button" class="btn btn-primary" onclick="rrfOptions(this)">OPTIONS</button>
7
+ <% end %>
8
+ <button type="button" class="btn btn-primary" onclick="rrfGet(this)">GET</button>
9
+ </div>
@@ -10,7 +10,7 @@
10
10
  <%# Render first group of routes directly. %>
11
11
  <tbody>
12
12
  <% @route_groups.values[0].each do |route| %>
13
- <%= render partial: "rest_framework/route", locals: {route: route} %>
13
+ <%= render partial: "rest_framework/routes_and_forms/routes/route", locals: {route: route} %>
14
14
  <% end %>
15
15
  </tbody>
16
16
  <%# Render any other groups under dropdowns. %>
@@ -20,7 +20,7 @@
20
20
  </tr>
21
21
  <tbody id="route-group-<%= index %>" class="collapse">
22
22
  <% route_group.each do |route| %>
23
- <%= render partial: "rest_framework/route", locals: {route: route} %>
23
+ <%= render partial: "rest_framework/routes_and_forms/routes/route", locals: {route: route} %>
24
24
  <% end %>
25
25
  </tbody>
26
26
  <% end %>
@@ -146,6 +146,9 @@ module RESTFramework::BaseControllerMixin
146
146
 
147
147
  base.extend(ClassMethods)
148
148
 
149
+ # By default, the layout should be set to `rest_framework`.
150
+ base.layout("rest_framework")
151
+
149
152
  # Add class attributes (with defaults) unless they already exist.
150
153
  RRF_BASE_CONFIG.each do |a, default|
151
154
  next if base.respond_to?(a)
@@ -267,8 +270,8 @@ module RESTFramework::BaseControllerMixin
267
270
 
268
271
  # Render a browsable API for `html` format, along with basic `json`/`xml` formats, and with
269
272
  # support or passing custom `kwargs` to the underlying `render` calls.
270
- def api_response(payload, html_kwargs: nil, **kwargs)
271
- html_kwargs ||= {}
273
+ def api_response(payload, **kwargs)
274
+ html_kwargs = kwargs.delete(:html_kwargs) || {}
272
275
  json_kwargs = kwargs.delete(:json_kwargs) || {}
273
276
  xml_kwargs = kwargs.delete(:xml_kwargs) || {}
274
277
 
@@ -300,12 +303,10 @@ module RESTFramework::BaseControllerMixin
300
303
  format.xml { head(kwargs[:status] || :no_content) } if self.serialize_to_xml
301
304
  else
302
305
  format.json {
303
- jkwargs = kwargs.merge(json_kwargs)
304
- render(json: payload, layout: false, **jkwargs)
306
+ render(json: payload, **kwargs.merge(json_kwargs))
305
307
  } if self.serialize_to_json
306
308
  format.xml {
307
- xkwargs = kwargs.merge(xml_kwargs)
308
- render(xml: payload, layout: false, **xkwargs)
309
+ render(xml: payload, **kwargs.merge(xml_kwargs))
309
310
  } if self.serialize_to_xml
310
311
  # TODO: possibly support more formats here if supported?
311
312
  end
@@ -323,13 +324,11 @@ module RESTFramework::BaseControllerMixin
323
324
  @route_props, @route_groups = RESTFramework::Utils.get_routes(
324
325
  Rails.application.routes, request
325
326
  )
326
- hkwargs = kwargs.merge(html_kwargs)
327
327
  begin
328
- render(**hkwargs)
329
- rescue ActionView::MissingTemplate # Fallback to `rest_framework` layout.
330
- hkwargs[:layout] = "rest_framework"
331
- hkwargs[:html] = ""
332
- render(**hkwargs)
328
+ render(**kwargs.merge(html_kwargs))
329
+ rescue ActionView::MissingTemplate
330
+ # A view is not required, so just use `html: ""`.
331
+ render(html: "", layout: true, **kwargs.merge(html_kwargs))
333
332
  end
334
333
  }
335
334
  end
@@ -2,9 +2,11 @@ class RESTFramework::Engine < Rails::Engine
2
2
  initializer "rest_framework.assets" do
3
3
  config.after_initialize do |app|
4
4
  if RESTFramework.config.use_vendored_assets
5
- app.config.assets.precompile += RESTFramework::EXTERNAL_ASSETS.keys.map do |name|
6
- "rest_framework/#{name}"
7
- end
5
+ app.config.assets.precompile += [
6
+ RESTFramework::EXTERNAL_CSS_NAME,
7
+ RESTFramework::EXTERNAL_JS_NAME,
8
+ *RESTFramework::EXTERNAL_UNSUMMARIZED_ASSETS.keys.map { |name| "rest_framework/#{name}" },
9
+ ]
8
10
  end
9
11
  end
10
12
  end
@@ -9,15 +9,15 @@ class RESTFramework::RansackFilter < RESTFramework::BaseFilter
9
9
 
10
10
  # Determine if `distinct` is determined by query param.
11
11
  if distinct_query_param = @controller.ransack_distinct_query_param
12
- distinct_from_query = ActiveRecord::Type::Boolean.new.cast(
13
- @controller.request.query_parameters[distinct_query_param],
14
- )
15
- unless distinct_from_query.nil?
16
- distinct = distinct_from_query
12
+ if distinct_query = @controller.request.query_parameters[distinct_query_param].presence
13
+ distinct_from_query = ActiveRecord::Type::Boolean.new.cast(distinct_query)
14
+ unless distinct_from_query.nil?
15
+ distinct = distinct_from_query
16
+ end
17
17
  end
18
18
  end
19
19
 
20
- return data.ransack(q, @controller.ransack_options).result(distinct: distinct)
20
+ return data.ransack(q, @controller.ransack_options || {}).result(distinct: distinct)
21
21
  end
22
22
 
23
23
  return data
@@ -2,6 +2,7 @@
2
2
  module RESTFramework
3
3
  module Version
4
4
  VERSION_FILEPATH = File.expand_path("../../VERSION", __dir__)
5
+ UNKNOWN = "0-unknown"
5
6
 
6
7
  def self.get_version(skip_git: false)
7
8
  # First, attempt to get the version from git.
@@ -17,19 +18,13 @@ module RESTFramework
17
18
  rescue SystemCallError
18
19
  end
19
20
 
20
- # If that fails, then try to get a plain commit SHA from git.
21
- unless skip_git
22
- version = `git describe --dirty --always`&.strip
23
- return "0.#{version}" unless !version || version.empty?
24
- end
25
-
26
21
  # No VERSION file, so version is unknown.
27
- return "0.unknown"
22
+ return UNKNOWN
28
23
  end
29
24
 
30
25
  def self.stamp_version
31
26
  # Only stamp the version if it's not unknown.
32
- if RESTFramework::VERSION != "0.unknown"
27
+ if RESTFramework::VERSION != UNKNOWN
33
28
  File.write(VERSION_FILEPATH, RESTFramework::VERSION)
34
29
  end
35
30
  end
@@ -20,6 +20,10 @@ module RESTFramework
20
20
  destroy_all: :delete,
21
21
  }.freeze
22
22
 
23
+ # We put most vendored external assets into these files to make precompilation and serving faster.
24
+ EXTERNAL_CSS_NAME = "rest_framework/external.min.css"
25
+ EXTERNAL_JS_NAME = "rest_framework/external.min.js"
26
+
23
27
  # We should always add the `.min` extension prefix even if the assets are not minified, to avoid
24
28
  # sprockets minifying the assets. We target propshaft, so we want these assets to just be passed
25
29
  # through.
@@ -81,7 +85,8 @@ module RESTFramework
81
85
  exclude_from_docs: true,
82
86
  },
83
87
  }.map { |name, cfg|
84
- if File.extname(name) == ".js"
88
+ ext = File.extname(name)
89
+ if ext == ".js"
85
90
  cfg[:place] = "javascripts"
86
91
  cfg[:extra_tag_attrs] ||= {}
87
92
  cfg[:tag_attrs] = {
@@ -93,7 +98,7 @@ module RESTFramework
93
98
  **cfg[:extra_tag_attrs],
94
99
  }
95
100
  cfg[:tag] = ActionController::Base.helpers.tag.script(**cfg[:tag_attrs])
96
- else
101
+ elsif ext == ".css"
97
102
  cfg[:place] = "stylesheets"
98
103
  cfg[:extra_tag_attrs] ||= {}
99
104
  cfg[:tag_attrs] = {
@@ -104,12 +109,16 @@ module RESTFramework
104
109
  **cfg[:extra_tag_attrs],
105
110
  }
106
111
  cfg[:tag] = ActionController::Base.helpers.tag.link(**cfg[:tag_attrs])
112
+ else
113
+ raise "Unknown asset extension: #{ext}."
107
114
  end
108
115
 
109
116
  [name, cfg]
110
117
  }.to_h.freeze
111
118
  # rubocop:enable Layout/LineLength
112
119
 
120
+ EXTERNAL_UNSUMMARIZED_ASSETS = EXTERNAL_ASSETS.select { |_, cfg| cfg[:extra_tag_attrs].present? }
121
+
113
122
  # Global configuration should be kept minimal, as controller-level configurations allows multiple
114
123
  # APIs to be defined to behave differently.
115
124
  class Config