rest_framework 0.9.5 → 0.9.6

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.
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 +348 -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 +0 -6
  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
@@ -17,12 +17,6 @@ module RESTFramework
17
17
  rescue SystemCallError
18
18
  end
19
19
 
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
20
  # No VERSION file, so version is unknown.
27
21
  return "0.unknown"
28
22
  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