js_from_routes 1.0.3 → 2.0.4

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 (34) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +50 -4
  3. data/LICENSE.txt +22 -0
  4. data/README.md +4 -156
  5. data/lib/js_from_routes/generator.rb +112 -64
  6. data/lib/js_from_routes/railtie.rb +2 -0
  7. data/lib/js_from_routes/template.js.erb +3 -16
  8. data/lib/js_from_routes/template_all.js.erb +5 -0
  9. data/lib/js_from_routes/template_index.js.erb +5 -0
  10. data/lib/js_from_routes/version.rb +1 -1
  11. metadata +6 -49
  12. data/spec/js_from_routes/js_from_routes_spec.rb +0 -78
  13. data/spec/spec_helper.rb +0 -7
  14. data/spec/support/sample_app/app/controllers/application_controller.rb +0 -2
  15. data/spec/support/sample_app/app/controllers/comments_controller.rb +0 -2
  16. data/spec/support/sample_app/app/controllers/user_preferences_controller.rb +0 -2
  17. data/spec/support/sample_app/app/controllers/video_clips_controller.rb +0 -17
  18. data/spec/support/sample_app/app/controllers/welcome_controller.rb +0 -2
  19. data/spec/support/sample_app/app/mailers/application_mailer.rb +0 -4
  20. data/spec/support/sample_app/config/application.rb +0 -15
  21. data/spec/support/sample_app/config/boot.rb +0 -3
  22. data/spec/support/sample_app/config/environment.rb +0 -5
  23. data/spec/support/sample_app/config/environments/development.rb +0 -25
  24. data/spec/support/sample_app/config/environments/test.rb +0 -5
  25. data/spec/support/sample_app/config/initializers/application_controller_renderer.rb +0 -8
  26. data/spec/support/sample_app/config/initializers/backtrace_silencers.rb +0 -7
  27. data/spec/support/sample_app/config/initializers/content_security_policy.rb +0 -37
  28. data/spec/support/sample_app/config/initializers/cookies_serializer.rb +0 -5
  29. data/spec/support/sample_app/config/initializers/filter_parameter_logging.rb +0 -4
  30. data/spec/support/sample_app/config/initializers/inflections.rb +0 -16
  31. data/spec/support/sample_app/config/initializers/mime_types.rb +0 -4
  32. data/spec/support/sample_app/config/initializers/wrap_parameters.rb +0 -14
  33. data/spec/support/sample_app/config/puma.rb +0 -38
  34. data/spec/support/sample_app/config/routes.rb +0 -22
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 11da4a678c4081b4ce6d99bac78e007f819cf5fecd2321af94c2e7962e557a71
4
- data.tar.gz: 3c81aa21374aae94ec47493f70ed978938061a9d1a03ca9bba481939e853c7ab
3
+ metadata.gz: 13b4bc245728511e15d787762ffddbe1bfb3799a7b61f69620a7f617435aed12
4
+ data.tar.gz: 1f2f759b537ce46f2628df9c17ea3f8325db4c7fb36e048270babc1a9116e637
5
5
  SHA512:
6
- metadata.gz: 8d71a098de83a7feab5bae4ce682c981a32d9d296db8392dc441371ce4f53b3237beefc155f670e69960af30d6780144bd426f6727fcf98d3a7260ac63c7fc12
7
- data.tar.gz: 70347defa686e95bae4264eda364e514eef9fa623078957a17825dc1c8894f77c0079b19c70f001586344980c5fe29c57812aaef0f74ba2ac8b92f910c39dc5e
6
+ metadata.gz: d5c443ada290e81b71dc6776e02007966471f6c2c188be2fc03f849b1c5f6bf0954fa1e37508f79a2f4ec015bd2e4b582f5ae29ed655843d07a0dd43f9f6d793
7
+ data.tar.gz: ee9cfcdf677e351aa7631c34835c9fbac8fd29fbb6d380c9bedb6965435f681c52f6a50c14ec63a8f971bef211b9ebf5e1ef2a243ac72e841f567250056a1b48
data/CHANGELOG.md CHANGED
@@ -1,18 +1,64 @@
1
- ## JsFromRoutes 1.0.3 (2021-03-10) ##
1
+ ## [2.0.4](https://github.com/ElMassimo/js_from_routes/compare/js_from_routes@2.0.3...js_from_routes@2.0.4) (2021-03-16)
2
+
3
+
4
+
5
+ ## [2.0.3](https://github.com/ElMassimo/js_from_routes/compare/js_from_routes@2.0.2...js_from_routes@2.0.3) (2021-03-16)
6
+
7
+
8
+ ### Bug Fixes
9
+
10
+ * Ensure changing the client library triggers code generation ([6cf2bdf](https://github.com/ElMassimo/js_from_routes/commit/6cf2bdf4896dafe0d1e80668551665c46bfcadc6))
11
+
12
+
13
+ ### Features
14
+
15
+ * Allow passing JS_FROM_ROUTES_FORCE=true to ignore cache keys ([8a6d2a8](https://github.com/ElMassimo/js_from_routes/commit/8a6d2a807e0a9926c6b24e1fc9127f917ec0ed5d))
16
+
17
+
18
+
19
+ ## [2.0.2](https://github.com/ElMassimo/js_from_routes/compare/js_from_routes@2.0.1...js_from_routes@2.0.2) (2021-03-14)
20
+
21
+ ### Improvements
22
+
23
+ - Remove underscores from namespaced controllers in global file ([90fdcc2](https://github.com/ElMassimo/js_from_routes/commit/90fdcc2))
24
+
25
+ ## [2.0.1](https://github.com/ElMassimo/js_from_routes/compare/js_from_routes@2.0.0...js_from_routes@2.0.1) (2021-03-14)
26
+
27
+ ### Features ⚡️
28
+
29
+ - Enable generation of index combining and exporting all helpers (#9)
30
+
31
+ # [2.0.0](https://github.com/ElMassimo/js_from_routes/compare/v1.0.3...js_from_routes@2.0.0) (2021-03-13)
32
+
33
+ ### Features ⚡️
34
+
35
+ - Path helpers now support both making a request or obtaining the path
36
+ - Auto-detect the folder where javascript files live (`frontend`, `packs`, `javascript`, or `assets`)
37
+ - The new default template is more flexible and can be easily customized using the `client_library` setting
38
+
39
+ ### Breaking Changes 💥
40
+
41
+ - Created client libraries that provide the necessary functionality out of the box (optional)
42
+ - Changed the default template, now using `definePathHelper`
43
+ - Defaults for code generation have changed (`Requests` → `Api`)
44
+ - `path_only?` and `request_method?` have been removed from `Route` during code generation
45
+ - You may still check for it in your custom templates, using `route.export == :path_only`
46
+
47
+ ## 1.0.3 (2021-03-10) ##
2
48
 
3
49
  * Use `~/` instead of `@/` in the default template imports.
4
50
 
5
51
 
6
- ## JsFromRoutes 1.0.2 (2021-03-10) ##
52
+ ## 1.0.2 (2021-03-10) ##
7
53
 
8
54
  * Ensure a default `template.js.erb` ships with the gem.
9
55
 
10
56
 
11
- ## JsFromRoutes 1.0.1 (2020-06-21) ##
57
+ ## 1.0.1 (2020-06-21) ##
12
58
 
13
59
  * Expose `export_setting` in the `Route` API, to support custom workflows.
14
60
 
15
61
 
16
- ## JsFromRoutes 1.0.0 (2020-06-21) ##
62
+ ## 1.0.0 (2020-06-21) ##
17
63
 
18
64
  * Initial Release.
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2021 Máximo Mussini
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md CHANGED
@@ -6,33 +6,16 @@ JS From Rails Routes
6
6
  <a href="https://codeclimate.com/github/ElMassimo/js_from_routes"><img alt="Maintainability" src="https://codeclimate.com/github/ElMassimo/js_from_routes/badges/gpa.svg"/></a>
7
7
  <a href="https://codeclimate.com/github/ElMassimo/js_from_routes"><img alt="Test Coverage" src="https://codeclimate.com/github/ElMassimo/js_from_routes/badges/coverage.svg"/></a>
8
8
  <a href="https://rubygems.org/gems/js_from_routes"><img alt="Gem Version" src="https://img.shields.io/gem/v/js_from_routes.svg?colorB=e9573f"/></a>
9
- <a href="https://github.com/ElMassimo/js_from_routes/blob/master/LICENSE.txt"><img alt="License" src="https://img.shields.io/badge/license-MIT-428F7E.svg"/></a>
9
+ <a href="https://github.com/ElMassimo/js_from_routes/blob/main/LICENSE.txt"><img alt="License" src="https://img.shields.io/badge/license-MIT-428F7E.svg"/></a>
10
10
  </p>
11
11
  </h1>
12
12
 
13
13
  [Vite Rails]: https://vite-ruby.netlify.app/
14
14
  [aliases]: https://vite-ruby.netlify.app/guide/development.html#import-aliases-%F0%9F%91%89
15
+ [config options]: https://github.com/ElMassimo/js_from_routes/blob/main/lib/js_from_routes/generator.rb#L82-L85
16
+ [readme]: https://github.com/ElMassimo/js_from_routes
15
17
 
16
- _JS from Routes_ helps you by automatically generating path and API helpers from
17
- Rails route definitions, allowing you to save development effort and focus on
18
- the things that matter.
19
-
20
- Check out [this pull request](https://github.com/ElMassimo/pingcrm-vite/pull/2) to get a sense of how flexible it can be.
21
-
22
- ### Why? 🤔
23
-
24
- Path helpers in Rails are useful, and make it easier to build urls, avoiding
25
- typos and mistakes.
26
-
27
- With this library, it's possible the enjoy the same benefits in JS:
28
-
29
- - No need to manually specify the URL, preventing mistakes and saving development time.
30
- - If an action is renamed or removed, the helper ceases to exist, which causes
31
- an error that is easier to detect than a 404.
32
- - We can embed the the HTTP verb in the helper. Changing the verb in the route causes the JS
33
- code to be regenerated, no need to update the consumer!
34
-
35
- Read more about it in the [blog announcement](https://maximomussini.com/posts/js-from-routes/).
18
+ For more information, check the main [README].
36
19
 
37
20
  ### Installation 💿
38
21
 
@@ -49,138 +32,3 @@ And then execute:
49
32
  Or install it yourself as:
50
33
 
51
34
  $ gem install js_from_routes
52
-
53
- ### Usage 🚀
54
-
55
- #### 1. Specify the Rails routes you want to export
56
-
57
- Use the `export` attribute to determine which [routes](https://github.com/ElMassimo/js_from_routes/blob/master/spec/support/sample_app/config/routes.rb#L6) should be taken into account when generating JS.
58
-
59
- ```ruby
60
- Rails.application.routes.draw do
61
- resources :video_clips, export: true do
62
- get :download, on: :member, export: :path_only
63
- get :trending, on: :collection, export: false
64
- end
65
- end
66
- ```
67
-
68
- #### 2. Generate JS code from your routes
69
-
70
- This is usually done automatically the next time you make a request to your
71
- Rails server (such as when you refresh the page), which causes Rails reloader to
72
- kick in, and the routes to be generated.
73
-
74
- If you are not running a local development server, or prefer to do it manually,
75
- you can use a rake task instead:
76
-
77
- ```
78
- bin/rake js_from_routes:generate
79
- ```
80
-
81
- which can generate code such as:
82
-
83
- ```js
84
- import { formatUrl } from '~/helpers/UrlHelper'
85
- import { request } from '~/services/ApiService'
86
-
87
- export default {
88
- downloadPath: options =>
89
- formatUrl('/video_clips/:id/download', options),
90
-
91
- get: options =>
92
- request('get', '/video_clips/:id', options),
93
-
94
- update: options =>
95
- request('patch', '/video_clips/:id', options),
96
- }
97
- ```
98
-
99
- #### 3. Use the generated code in your JS application
100
-
101
- This can happen in many [different ways](https://github.com/ElMassimo/js_from_routes/blob/master/spec/support/sample_app/app/javascript/Videos.vue#L10), but to illustrate using the example above, in combination with [`axios`](https://github.com/axios/axios) or `fetch`:
102
-
103
- ```js
104
- import VideoClipsRequests from '@requests/VideoClipsRequests'
105
-
106
- VideoClipsRequests.get({ id: 'oHg5SJYRHA0' }).then(data => { this.video = data })
107
-
108
- const newVideo = { ...this.video, format: '.mp4' }
109
- VideoClipsRequests.update(newVideo)
110
-
111
- const path = VideoClipsRequests.downloadPath(newVideo)
112
- ```
113
-
114
- Check the [examples](https://github.com/ElMassimo/js_from_routes/blob/master/spec/support/sample_app/app/javascript/Videos.vue) for ideas on how to [use it](https://github.com/ElMassimo/js_from_routes/blob/master/spec/support/sample_app/app/javascript/Videos.vue), and how you can configure it to your convenience.
115
-
116
- Read on to find out how to customize the generated code to suit your needs.
117
-
118
- ### Advanced Configuration 📖
119
-
120
- Since all projects are different, it's very unlikely that the default settings
121
- fulfill all your requirements.
122
-
123
- The following [settings](https://github.com/ElMassimo/js_from_routes/blob/master/lib/js_from_routes/generator.rb#L77-L80) are available:
124
-
125
- ##### [`file_suffix`](https://github.com/ElMassimo/js_from_routes/blob/master/lib/js_from_routes/generator.rb#L77), default: `Requests.js`
126
-
127
- This suffix is added by default to all generated files. You can modify it to
128
- if you prefer a different convention, or if you use it to generate TypeScript.
129
-
130
- ##### [`helper_mappings`](https://github.com/ElMassimo/js_from_routes/blob/master/lib/js_from_routes/generator.rb#L80)
131
-
132
- By default it maps `index` to `list` and `show` to `get`, which helps to make
133
- the JS code read more naturally.
134
-
135
- ##### [`output_folder`](https://github.com/ElMassimo/js_from_routes/blob/master/lib/js_from_routes/generator.rb#L78), default: `app/javascript/requests`
136
-
137
- The directory where the generated files are created.
138
-
139
- Tip: It's highly recommended to [add a webpack alias](https://github.com/ElMassimo/js_from_routes/blob/webpack/spec/support/sample_app/config/webpack/aliases.js#L11), to simplify [imports](https://github.com/ElMassimo/js_from_routes/blob/master/spec/support/sample_app/app/javascript/Videos.vue#2).
140
-
141
- If you use [Vite Rails], the [aliases] are already configured for you.
142
-
143
- ##### [`template_path`](https://github.com/ElMassimo/js_from_routes/blob/master/lib/js_from_routes/generator.rb#L79)
144
-
145
- A [default template](https://github.com/ElMassimo/js_from_routes/blob/master/lib/js_from_routes/template.js.erb) is provided, but it makes assumptions about the [available](https://github.com/ElMassimo/js_from_routes/blob/master/spec/support/sample_app/app/javascript/services/ApiService.js#L17) [code](https://github.com/ElMassimo/js_from_routes/blob/master/spec/support/sample_app/app/javascript/helpers/UrlHelper.js#L28).
146
-
147
- You will probably want to use a custom template, such as:
148
-
149
- ```ruby
150
- # config/initializers/js_from_routes.rb
151
- if Rails.env.development?
152
- JsFromRoutes.config do |config|
153
- config.template_path = Rails.root.join('app', 'views', 'custom_js_from_routes.js.erb')
154
- end
155
- end
156
- ```
157
-
158
- A `routes` variable will be available in the template, which will contain the
159
- endpoints exported for a controller.
160
-
161
- Each `route` exposes properties such as `verb` and `path`, please [check the
162
- source code](https://github.com/ElMassimo/js_from_routes/blob/master/lib/js_from_routes/generator.rb#L34-L71) for details on the [API](https://github.com/ElMassimo/js_from_routes/blob/master/lib/js_from_routes/generator.rb#L34-L71).
163
-
164
- ### How does it work? ⚙️
165
-
166
- By adding a hook to Rails' reload process in development, it's possible to
167
- automatically generate files from routes when a route is added, modified, or removed.
168
-
169
- In order to optimize file generation, the generated JS files are split by
170
- controller, and add a cache key based on the routes to avoid rewriting the file
171
- if the route definition hasn't changed.
172
-
173
- When the Vite.js or Webpack development server is running, it detects when a new
174
- file is generated, automatically triggering a new build, which can now use the
175
- generated request methods or path helpers 😃
176
-
177
- ### Take this idea 💡
178
-
179
- While the original use cases intended to generate code that targes a custom `ApiService`,
180
- it can be tweaked to generate TypeScript, [target jQuery](https://gist.github.com/ElMassimo/cab56e64e20ff797f3054b661a883646),
181
- or use it only to generate [path helpers](https://github.com/ElMassimo/js_from_routes/blob/master/spec/support/sample_app/app/javascript/requests/UserPreferencesRequests.js#L11-L15).
182
-
183
- There are plenty of other opportunities for automatic code generation, such as keeping
184
- enums in sync between Ruby and JS.
185
-
186
- Let me know if you come up with new or creative ways to use this technique 😃
@@ -3,16 +3,17 @@
3
3
  require "digest"
4
4
  require "erubi"
5
5
  require "fileutils"
6
+ require "pathname"
6
7
 
7
8
  # Public: Automatically generates JS for Rails routes with { export: true }.
8
9
  # Generates one file per controller, and one function per route.
9
10
  module JsFromRoutes
10
11
  # Internal: Helper class used as a presenter for the routes template.
11
- class Routes
12
+ class ControllerRoutes
12
13
  attr_reader :routes
13
14
 
14
- def initialize(routes, config)
15
- @config = config
15
+ def initialize(controller, routes, config)
16
+ @controller, @config = controller, config
16
17
  @routes = routes
17
18
  .uniq { |route| route.requirements.fetch(:action) }
18
19
  .map { |route| Route.new(route, config.helper_mappings) }
@@ -21,13 +22,32 @@ module JsFromRoutes
21
22
  # Public: Used to check whether the file should be generated again, changes
22
23
  # based on the configuration, and route definition.
23
24
  def cache_key
24
- Digest::MD5.hexdigest(routes.map(&:inspect).join + [File.read(@config.template_path), @config.helper_mappings.inspect].join)
25
+ routes.map(&:inspect).join + [File.read(@config.template_path), @config.helper_mappings.inspect, @config.client_library].join
25
26
  end
26
27
 
27
- # Internal: By performing the evaluation here, we ensure only "routes" is
28
- # exposed to the ERB template as a local variable.
29
- def evaluate(compiled_template)
30
- instance_eval(compiled_template)
28
+ # Public: Exposes the preferred import library to the generator.
29
+ def client_library
30
+ @config.client_library
31
+ end
32
+
33
+ # Internal: Name of the JS file with helpers for the the given controller.
34
+ def filename
35
+ @config.output_folder.join(basename)
36
+ end
37
+
38
+ # Public: Name of the JS file with helpers for the the given controller.
39
+ def import_filename
40
+ @config.output_folder.basename.join((basename.split(".")[0]).to_s)
41
+ end
42
+
43
+ # Public: Name of the file as a valid JS variable.
44
+ def js_name
45
+ @controller.camelize(:lower).tr(":", "")
46
+ end
47
+
48
+ # Internal: The base name of the JS file to be written.
49
+ def basename
50
+ "#{@controller.camelize}#{@config.file_suffix}".tr_s(":", "/")
31
51
  end
32
52
  end
33
53
 
@@ -37,21 +57,11 @@ module JsFromRoutes
37
57
  @route, @mappings = route, mappings
38
58
  end
39
59
 
40
- # Public: Whether it should export only the path.
41
- def path_only?
42
- export_setting == :path_only
43
- end
44
-
45
60
  # Public: The `export` setting specified for the action.
46
- def export_setting
61
+ def export
47
62
  @route.defaults[:export]
48
63
  end
49
64
 
50
- # Public: Whether it should export only the path.
51
- def request_method?
52
- !path_only?
53
- end
54
-
55
65
  # Public: The HTTP verb for the action. Example: 'patch'
56
66
  def verb
57
67
  @route.verb.downcase
@@ -65,8 +75,7 @@ module JsFromRoutes
65
75
  # Public: The name of the JS helper for the action. Example: 'destroyAll'
66
76
  def helper
67
77
  action = @route.requirements.fetch(:action).camelize(:lower)
68
- name = @mappings.fetch(action, action)
69
- path_only? ? "#{name}Path" : name
78
+ @mappings.fetch(action, action)
70
79
  end
71
80
 
72
81
  # Internal: Useful as a cache key for the route, and for debugging purposes.
@@ -75,15 +84,52 @@ module JsFromRoutes
75
84
  end
76
85
  end
77
86
 
87
+ # Internal: Represents a compiled template that can write itself to a file.
88
+ class Template
89
+ def initialize(template_path)
90
+ # NOTE: The compiled ERB template, used to generate JS code.
91
+ @compiled_template = Erubi::Engine.new(File.read(template_path), filename: template_path).src
92
+ end
93
+
94
+ # Public: Checks if the cache is fresh, or renders the template with the
95
+ # specified variables, and writes the updated result to a file.
96
+ def write_if_changed(object)
97
+ write_file_if_changed(object.filename, object.cache_key) { render_template(object) }
98
+ end
99
+
100
+ private
101
+
102
+ # Internal: Returns a String with the generated JS code.
103
+ def render_template(object)
104
+ object.instance_eval(@compiled_template)
105
+ end
106
+
107
+ # Internal: Returns true if the cache key has changed since the last codegen.
108
+ def stale?(file, cache_key_comment)
109
+ ENV["JS_FROM_ROUTES_FORCE"] || file.gets != cache_key_comment
110
+ end
111
+
112
+ # Internal: Writes if the file does not exist or the cache key has changed.
113
+ # The cache strategy consists of a comment on the first line of the file.
114
+ #
115
+ # Yields to receive the rendered file content when it needs to.
116
+ def write_file_if_changed(name, cache_key)
117
+ FileUtils.mkdir_p(name.dirname)
118
+ cache_key_comment = "// JsFromRoutes CacheKey #{Digest::MD5.hexdigest(cache_key)}\n"
119
+ File.open(name, "a+") { |file|
120
+ if stale?(file, cache_key_comment)
121
+ file.truncate(0)
122
+ file.write(cache_key_comment)
123
+ file.write(yield)
124
+ end
125
+ }
126
+ end
127
+ end
128
+
78
129
  class << self
79
130
  # Public: Configuration of the code generator.
80
131
  def config
81
- @config ||= OpenStruct.new(
82
- file_suffix: "Requests.js",
83
- output_folder: ::Rails.root&.join("app", "javascript", "requests"),
84
- template_path: File.expand_path("template.js.erb", __dir__),
85
- helper_mappings: {"index" => "list", "show" => "get"}
86
- )
132
+ @config ||= OpenStruct.new(default_config(::Rails.root || Pathname.new(Dir.pwd)))
87
133
  yield(@config) if block_given?
88
134
  @config
89
135
  end
@@ -92,55 +138,57 @@ module JsFromRoutes
92
138
  def generate!(app_or_routes = Rails.application)
93
139
  raise ArgumentError, "A Rails app must be defined, or you must specify a custom `output_folder`" if config.output_folder.blank?
94
140
  rails_routes = app_or_routes.is_a?(::Rails::Engine) ? app_or_routes.routes.routes : app_or_routes
95
- @compiled_template = nil # Clear on every code reload in case the template changed.
96
- exported_routes_by_controller(rails_routes).each do |controller, controller_routes|
97
- routes = Routes.new(controller_routes, config)
98
- write_if_changed(filename_for(controller), routes.cache_key) { render_template(routes) }
99
- end
141
+ generate_files exported_routes_by_controller(rails_routes)
100
142
  end
101
143
 
102
144
  private
103
145
 
104
- # Internal: Returns exported routes grouped by controller name.
105
- def exported_routes_by_controller(routes)
106
- routes.select { |route|
107
- route.defaults.fetch(:export, false)
108
- }.group_by { |route|
109
- route.requirements.fetch(:controller)
146
+ def generate_files(exported_routes)
147
+ template = Template.new(config.template_path)
148
+ generate_file_for_all exported_routes.map { |controller, routes|
149
+ ControllerRoutes.new(controller, routes, config).tap do |routes|
150
+ template.write_if_changed routes
151
+ end
110
152
  }
111
153
  end
112
154
 
113
- # Internal: Name of the JS file with helpers for the the given controller.
114
- def filename_for(controller)
115
- config.output_folder.join("#{controller.camelize}#{config.file_suffix}".tr_s(":", "/"))
116
- end
155
+ def generate_file_for_all(routes)
156
+ return unless config.all_helpers_file && !routes.empty?
117
157
 
118
- # Internal: Returns a String with the JS generated for a controller's routes.
119
- def render_template(routes)
120
- routes.evaluate(compiled_template)
158
+ preferred_extension = File.extname(config.file_suffix)
159
+ index_file = config.all_helpers_file == true ? "index#{preferred_extension}" : config.all_helpers_file
160
+
161
+ Template.new(config.template_all_path).write_if_changed OpenStruct.new(
162
+ cache_key: routes.map(&:import_filename).join + File.read(config.template_all_path),
163
+ filename: config.output_folder.join("all#{preferred_extension}"),
164
+ helpers: routes,
165
+ )
166
+ Template.new(config.template_index_path).write_if_changed OpenStruct.new(
167
+ cache_key: File.read(config.template_index_path),
168
+ filename: config.output_folder.join(index_file),
169
+ )
121
170
  end
122
171
 
123
- # Internal: Returns the compiled ERB to generate JS from a set of routes.
124
- def compiled_template
125
- @compiled_template ||= begin
126
- template = File.read(config.template_path)
127
- Erubi::Engine.new(template, filename: config.template_path).src
128
- end
172
+ def default_config(root)
173
+ dir = %w[frontend packs javascript assets].find { |dir| root.join("app", dir).exist? }
174
+ {
175
+ all_helpers_file: true,
176
+ client_library: "@js-from-routes/client",
177
+ file_suffix: "Api.js",
178
+ helper_mappings: {"index" => "list", "show" => "get"},
179
+ output_folder: root.join("app", dir, "api"),
180
+ template_path: File.expand_path("template.js.erb", __dir__),
181
+ template_all_path: File.expand_path("template_all.js.erb", __dir__),
182
+ template_index_path: File.expand_path("template_index.js.erb", __dir__),
183
+ }
129
184
  end
130
185
 
131
- # Internal: Writes if the file does not exist or the cache key has changed.
132
- # The cache strategy consists of a comment on the first line of the file.
133
- #
134
- # Yields to receive the rendered file content when it needs to.
135
- def write_if_changed(name, cache_key)
136
- FileUtils.mkdir_p(name.dirname)
137
- cache_key_comment = "// JsFromRoutes CacheKey #{cache_key}\n"
138
- File.open(name, "a+") { |file|
139
- if file.gets != cache_key_comment
140
- file.truncate(0)
141
- file.write(cache_key_comment)
142
- file.write(yield)
143
- end
186
+ # Internal: Returns exported routes grouped by controller name.
187
+ def exported_routes_by_controller(routes)
188
+ routes.select { |route|
189
+ route.defaults.fetch(:export, false)
190
+ }.group_by { |route|
191
+ route.requirements.fetch(:controller)
144
192
  }
145
193
  end
146
194
  end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "rails/railtie"
4
+
3
5
  # NOTE: Not strictly required, but it helps to simplify the setup.
4
6
  class JsFromRoutes::Railtie < Rails::Railtie
5
7
  railtie_name :js_from_routes
@@ -1,22 +1,9 @@
1
1
  //
2
2
  // DO NOT MODIFY: This file was automatically generated by JsFromRoutes.
3
- <%
4
- if routes.any?(&:path_only?)
5
- %>import { formatUrl } from '~/helpers/UrlHelper'<%
6
- end
7
- %><% if routes.any?(&:path_only?) && routes.any?(&:request_method?) %><%= "\n" %><% end %><%
8
- if routes.any?(&:request_method?)
9
- %>import { request } from '~/services/ApiService'<%
10
- end
11
- %>
3
+ import { definePathHelper } from '<%= client_library %>'
12
4
 
13
5
  export default {
14
- <% routes.each_with_index do |route, index| %>
15
- <% if index > 0 %><%= "\n" %><% end
16
- %> <%= route.helper %>: options =>
17
- <% if route.path_only?
18
- %>formatUrl(<% else
19
- %>request('<%= route.verb %>', <% end
20
- %>'<%= route.path %>', options),
6
+ <% routes.each do |route| %>
7
+ <%= route.helper %>: definePathHelper('<%= route.verb %>', '<%= route.path %>'),
21
8
  <% end %>
22
9
  }
@@ -0,0 +1,5 @@
1
+ //
2
+ // DO NOT MODIFY: This file was automatically generated by JsFromRoutes.
3
+ <% helpers.each do |helper| %>
4
+ export { default as <%= helper.js_name %> } from '~/<%= helper.import_filename %>'
5
+ <% end %>
@@ -0,0 +1,5 @@
1
+ //
2
+ // DO NOT MODIFY: This file was automatically generated by JsFromRoutes.
3
+ import * as helpers from '~/api/all'
4
+ export * from '~/api/all'
5
+ export default helpers
@@ -4,5 +4,5 @@
4
4
  # Generates one file per controller, and one function per route.
5
5
  module JsFromRoutes
6
6
  # Public: This library adheres to semantic versioning.
7
- VERSION = "1.0.3"
7
+ VERSION = "2.0.4"
8
8
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: js_from_routes
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.3
4
+ version: 2.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Máximo Mussini
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-03-10 00:00:00.000000000 Z
11
+ date: 2021-03-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: railties
@@ -139,35 +139,15 @@ extra_rdoc_files:
139
139
  - README.md
140
140
  files:
141
141
  - CHANGELOG.md
142
+ - LICENSE.txt
142
143
  - README.md
143
144
  - lib/js_from_routes.rb
144
145
  - lib/js_from_routes/generator.rb
145
146
  - lib/js_from_routes/railtie.rb
146
147
  - lib/js_from_routes/template.js.erb
148
+ - lib/js_from_routes/template_all.js.erb
149
+ - lib/js_from_routes/template_index.js.erb
147
150
  - lib/js_from_routes/version.rb
148
- - spec/js_from_routes/js_from_routes_spec.rb
149
- - spec/spec_helper.rb
150
- - spec/support/sample_app/app/controllers/application_controller.rb
151
- - spec/support/sample_app/app/controllers/comments_controller.rb
152
- - spec/support/sample_app/app/controllers/user_preferences_controller.rb
153
- - spec/support/sample_app/app/controllers/video_clips_controller.rb
154
- - spec/support/sample_app/app/controllers/welcome_controller.rb
155
- - spec/support/sample_app/app/mailers/application_mailer.rb
156
- - spec/support/sample_app/config/application.rb
157
- - spec/support/sample_app/config/boot.rb
158
- - spec/support/sample_app/config/environment.rb
159
- - spec/support/sample_app/config/environments/development.rb
160
- - spec/support/sample_app/config/environments/test.rb
161
- - spec/support/sample_app/config/initializers/application_controller_renderer.rb
162
- - spec/support/sample_app/config/initializers/backtrace_silencers.rb
163
- - spec/support/sample_app/config/initializers/content_security_policy.rb
164
- - spec/support/sample_app/config/initializers/cookies_serializer.rb
165
- - spec/support/sample_app/config/initializers/filter_parameter_logging.rb
166
- - spec/support/sample_app/config/initializers/inflections.rb
167
- - spec/support/sample_app/config/initializers/mime_types.rb
168
- - spec/support/sample_app/config/initializers/wrap_parameters.rb
169
- - spec/support/sample_app/config/puma.rb
170
- - spec/support/sample_app/config/routes.rb
171
151
  homepage: https://github.com/ElMassimo/js_from_routes
172
152
  licenses:
173
153
  - MIT
@@ -191,27 +171,4 @@ rubygems_version: 3.1.4
191
171
  signing_key:
192
172
  specification_version: 4
193
173
  summary: Generate JS automatically from Rails routes.
194
- test_files:
195
- - spec/spec_helper.rb
196
- - spec/js_from_routes/js_from_routes_spec.rb
197
- - spec/support/sample_app/app/mailers/application_mailer.rb
198
- - spec/support/sample_app/app/controllers/video_clips_controller.rb
199
- - spec/support/sample_app/app/controllers/application_controller.rb
200
- - spec/support/sample_app/app/controllers/comments_controller.rb
201
- - spec/support/sample_app/app/controllers/welcome_controller.rb
202
- - spec/support/sample_app/app/controllers/user_preferences_controller.rb
203
- - spec/support/sample_app/config/routes.rb
204
- - spec/support/sample_app/config/environments/development.rb
205
- - spec/support/sample_app/config/environments/test.rb
206
- - spec/support/sample_app/config/environment.rb
207
- - spec/support/sample_app/config/application.rb
208
- - spec/support/sample_app/config/puma.rb
209
- - spec/support/sample_app/config/boot.rb
210
- - spec/support/sample_app/config/initializers/application_controller_renderer.rb
211
- - spec/support/sample_app/config/initializers/backtrace_silencers.rb
212
- - spec/support/sample_app/config/initializers/mime_types.rb
213
- - spec/support/sample_app/config/initializers/filter_parameter_logging.rb
214
- - spec/support/sample_app/config/initializers/wrap_parameters.rb
215
- - spec/support/sample_app/config/initializers/cookies_serializer.rb
216
- - spec/support/sample_app/config/initializers/content_security_policy.rb
217
- - spec/support/sample_app/config/initializers/inflections.rb
174
+ test_files: []
@@ -1,78 +0,0 @@
1
- require "support/sample_app/config/application"
2
- require "support/sample_app/config/routes"
3
-
4
- describe JsFromRoutes do
5
- original_template_path = JsFromRoutes.config.template_path
6
-
7
- let(:output_dir) { Pathname.new File.expand_path("../support/generated", __dir__) }
8
- let(:sample_dir) { Rails.root.join("app", "javascript", "requests") }
9
- let(:different_template_path) { File.expand_path("../support/jquery_template.js.erb", __dir__) }
10
- let(:controllers_with_exported_routes) { %w[Comments UserPreferences VideoClips] }
11
-
12
- def file_for(dir, name)
13
- dir.join("#{name}Requests.js")
14
- end
15
-
16
- def sample_file_for(name)
17
- file_for(sample_dir, name)
18
- end
19
-
20
- def output_file_for(name)
21
- file_for(output_dir, name)
22
- end
23
-
24
- before do
25
- # Sanity checks
26
- expect(sample_dir.exist?).to eq true
27
- expect(Rails.application.routes.routes).to be_present
28
-
29
- # Remove directory from a previous test run.
30
- begin
31
- FileUtils.remove_dir(output_dir)
32
- rescue
33
- nil
34
- end
35
-
36
- # Change the configuration to use a different directory.
37
- JsFromRoutes.config do |config|
38
- config.output_folder = output_dir
39
- config.template_path = original_template_path
40
- end
41
- end
42
-
43
- # NOTE: We do a manual snapshot test for now, more tests coming in the future.
44
- it "should generate the files as expected" do
45
- expect(JsFromRoutes).to receive(:render_template).exactly(3).times.and_call_original
46
- JsFromRoutes.generate!
47
-
48
- # It does not generate routes that don't have `export: true`.
49
- expect(output_file_for("Welcome").exist?).to eq false
50
-
51
- # It generates one file per controller with exported routes.
52
- controllers_with_exported_routes.each do |file_name|
53
- expect(output_file_for(file_name).read).to eq sample_file_for(file_name).read
54
- end
55
-
56
- # It detects changes to the template, and regenerates the files.
57
- JsFromRoutes.config do |config|
58
- config.template_path = different_template_path
59
- end
60
- expect(JsFromRoutes).to receive(:render_template).exactly(3).times.and_call_original
61
- JsFromRoutes.generate!
62
-
63
- # These files should no longer match the sample ones.
64
- controllers_with_exported_routes.each do |file_name|
65
- expect(output_file_for(file_name).read).not_to eq sample_file_for(file_name).read
66
- end
67
-
68
- # It should not rewrite the files if the cache key has not changed.
69
- expect(JsFromRoutes).not_to receive(:render_template)
70
- JsFromRoutes.generate!
71
- end
72
-
73
- it "should have a rake task available" do
74
- Rails.application.load_tasks
75
- expect(JsFromRoutes).to receive(:render_template).exactly(3).times
76
- expect { Rake::Task["js_from_routes:generate"].invoke }.not_to raise_error
77
- end
78
- end
data/spec/spec_helper.rb DELETED
@@ -1,7 +0,0 @@
1
- require "simplecov"
2
- SimpleCov.start { add_filter "/spec/" }
3
-
4
- require "rails"
5
- require "js_from_routes"
6
- require "rspec/given"
7
- require "pry-byebug"
@@ -1,2 +0,0 @@
1
- class ApplicationController < ActionController::Base
2
- end
@@ -1,2 +0,0 @@
1
- class CommentsController < ApplicationController
2
- end
@@ -1,2 +0,0 @@
1
- class UserPreferencesController < ApplicationController
2
- end
@@ -1,17 +0,0 @@
1
- class VideoClipsController < ApplicationController
2
- def trending
3
- render json: [
4
- {title: "Smoke Signals"},
5
- {title: "Camino Libre"},
6
- {title: "Sin Querer"},
7
- {title: "Tabula Rasa"},
8
- {title: "Raindance"},
9
- {title: "Ragamuffin"},
10
- {title: "Vals Venezolano Nº 2"},
11
- {title: "Xaranga do Vovô"},
12
- {title: "Café 1930"},
13
- {title: "Milonga (Uruguay)"},
14
- {title: "Divagando"}
15
- ]
16
- end
17
- end
@@ -1,2 +0,0 @@
1
- class WelcomeController < ApplicationController
2
- end
@@ -1,4 +0,0 @@
1
- class ApplicationMailer < ActionMailer::Base
2
- default from: "from@example.com"
3
- layout "mailer"
4
- end
@@ -1,15 +0,0 @@
1
- require_relative "boot"
2
-
3
- require "action_controller/railtie"
4
-
5
- # Require the gems listed in Gemfile, including any gems
6
- # you've limited to :test, :development, or :production.
7
- Bundler.require(*Rails.groups)
8
-
9
- module SampleApp
10
- class Application < Rails::Application
11
- # Application configuration can go into files in config/initializers
12
- # -- all .rb files in that directory are automatically loaded after loading
13
- # the framework and any gems in your application.
14
- end
15
- end
@@ -1,3 +0,0 @@
1
- ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
2
-
3
- require "bundler/setup" # Set up gems listed in the Gemfile.
@@ -1,5 +0,0 @@
1
- # Load the Rails application.
2
- require_relative "application"
3
-
4
- # Initialize the Rails application.
5
- Rails.application.initialize!
@@ -1,25 +0,0 @@
1
- Rails.application.configure do
2
- # Settings specified here will take precedence over those in config/application.rb.
3
-
4
- # In the development environment your application's code is reloaded on
5
- # every request. This slows down response time but is perfect for development
6
- # since you don't have to restart the web server when you make code changes.
7
- config.cache_classes = false
8
-
9
- # Do not eager load code on boot.
10
- config.eager_load = false
11
-
12
- # Show full error reports.
13
- config.consider_all_requests_local = true
14
-
15
- # Store uploaded files on the local file system (see config/storage.yml for options).
16
- # Print deprecation notices to the Rails logger.
17
- config.active_support.deprecation = :log
18
-
19
- # Raises error for missing translations.
20
- # config.action_view.raise_on_missing_translations = true
21
-
22
- # Use an evented file watcher to asynchronously detect changes in source code,
23
- # routes, locales, etc. This feature depends on the listen gem.
24
- config.file_watcher = ActiveSupport::EventedFileUpdateChecker
25
- end
@@ -1,5 +0,0 @@
1
- Rails.application.configure do
2
- # Settings specified here will take precedence over those in config/application.rb.
3
- config.cache_classes = true
4
- config.eager_load = true
5
- end
@@ -1,8 +0,0 @@
1
- # Be sure to restart your server when you modify this file.
2
-
3
- # ActiveSupport::Reloader.to_prepare do
4
- # ApplicationController.renderer.defaults.merge!(
5
- # http_host: 'example.org',
6
- # https: false
7
- # )
8
- # end
@@ -1,7 +0,0 @@
1
- # Be sure to restart your server when you modify this file.
2
-
3
- # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces.
4
- # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ }
5
-
6
- # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code.
7
- # Rails.backtrace_cleaner.remove_silencers!
@@ -1,37 +0,0 @@
1
- # Be sure to restart your server when you modify this file.
2
-
3
- # Define an application-wide content security policy
4
- # For further information see the following documentation
5
- # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy
6
-
7
- # Rails.application.config.content_security_policy do |policy|
8
- # policy.default_src :self, :https
9
- # policy.font_src :self, :https, :data
10
- # policy.img_src :self, :https, :data
11
- # policy.object_src :none
12
- # policy.script_src :self, :https
13
- # Allow @vite/client to hot reload changes in development
14
- # policy.script_src *policy.script_src, :unsafe_eval, "http://localhost:3036" if Rails.env.development?
15
-
16
- # You may need to enable this in production as well depending on your setup.
17
- # policy.script_src *policy.script_src, :blob if Rails.env.test?
18
- # policy.style_src :self, :https
19
- # # If you are using webpack-dev-server then specify webpack-dev-server host
20
- # policy.connect_src :self, :https, "http://localhost:3035", "ws://localhost:3035" if Rails.env.development?
21
- # Allow @vite/client to hot reload changes in development
22
- # policy.connect_src *policy.connect_src, "ws://#{ ViteRuby.config.host_with_port }" if Rails.env.development?
23
-
24
- # # Specify URI for violation reports
25
- # # policy.report_uri "/csp-violation-report-endpoint"
26
- # end
27
-
28
- # If you are using UJS then enable automatic nonce generation
29
- # Rails.application.config.content_security_policy_nonce_generator = -> request { SecureRandom.base64(16) }
30
-
31
- # Set the nonce only to specific directives
32
- # Rails.application.config.content_security_policy_nonce_directives = %w(script-src)
33
-
34
- # Report CSP violations to a specified URI
35
- # For further information see the following documentation:
36
- # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy-Report-Only
37
- # Rails.application.config.content_security_policy_report_only = true
@@ -1,5 +0,0 @@
1
- # Be sure to restart your server when you modify this file.
2
-
3
- # Specify a serializer for the signed and encrypted cookie jars.
4
- # Valid options are :json, :marshal, and :hybrid.
5
- Rails.application.config.action_dispatch.cookies_serializer = :json
@@ -1,4 +0,0 @@
1
- # Be sure to restart your server when you modify this file.
2
-
3
- # Configure sensitive parameters which will be filtered from the log file.
4
- Rails.application.config.filter_parameters += [:password]
@@ -1,16 +0,0 @@
1
- # Be sure to restart your server when you modify this file.
2
-
3
- # Add new inflection rules using the following format. Inflections
4
- # are locale specific, and you may define rules for as many different
5
- # locales as you wish. All of these examples are active by default:
6
- # ActiveSupport::Inflector.inflections(:en) do |inflect|
7
- # inflect.plural /^(ox)$/i, '\1en'
8
- # inflect.singular /^(ox)en/i, '\1'
9
- # inflect.irregular 'person', 'people'
10
- # inflect.uncountable %w( fish sheep )
11
- # end
12
-
13
- # These inflection rules are supported but not enabled by default:
14
- # ActiveSupport::Inflector.inflections(:en) do |inflect|
15
- # inflect.acronym 'RESTful'
16
- # end
@@ -1,4 +0,0 @@
1
- # Be sure to restart your server when you modify this file.
2
-
3
- # Add new mime types for use in respond_to blocks:
4
- # Mime::Type.register "text/richtext", :rtf
@@ -1,14 +0,0 @@
1
- # Be sure to restart your server when you modify this file.
2
-
3
- # This file contains settings for ActionController::ParamsWrapper which
4
- # is enabled by default.
5
-
6
- # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array.
7
- ActiveSupport.on_load(:action_controller) do
8
- wrap_parameters format: [:json]
9
- end
10
-
11
- # To enable root element in JSON for ActiveRecord objects.
12
- # ActiveSupport.on_load(:active_record) do
13
- # self.include_root_in_json = true
14
- # end
@@ -1,38 +0,0 @@
1
- # Puma can serve each request in a thread from an internal thread pool.
2
- # The `threads` method setting takes two numbers: a minimum and maximum.
3
- # Any libraries that use thread pools should be configured to match
4
- # the maximum value specified for Puma. Default is set to 5 threads for minimum
5
- # and maximum; this matches the default thread size of Active Record.
6
- #
7
- max_threads_count = ENV.fetch("RAILS_MAX_THREADS", 5)
8
- min_threads_count = ENV.fetch("RAILS_MIN_THREADS", max_threads_count)
9
- threads min_threads_count, max_threads_count
10
-
11
- # Specifies the `port` that Puma will listen on to receive requests; default is 3000.
12
- #
13
- port ENV.fetch("PORT", 3000)
14
-
15
- # Specifies the `environment` that Puma will run in.
16
- #
17
- environment ENV.fetch("RAILS_ENV") { "development" }
18
-
19
- # Specifies the `pidfile` that Puma will use.
20
- pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" }
21
-
22
- # Specifies the number of `workers` to boot in clustered mode.
23
- # Workers are forked web server processes. If using threads and workers together
24
- # the concurrency of the application would be max `threads` * `workers`.
25
- # Workers do not work on JRuby or Windows (both of which do not support
26
- # processes).
27
- #
28
- # workers ENV.fetch("WEB_CONCURRENCY") { 2 }
29
-
30
- # Use the `preload_app!` method when specifying a `workers` number.
31
- # This directive tells Puma to first boot the application and load code
32
- # before forking the application. This takes advantage of Copy On Write
33
- # process behavior so workers use less memory.
34
- #
35
- # preload_app!
36
-
37
- # Allow puma to be restarted by `rails restart` command.
38
- plugin :tmp_restart
@@ -1,22 +0,0 @@
1
- Rails.application.routes.draw do
2
- root to: "welcome#home"
3
-
4
- resources :welcome
5
-
6
- resources :video_clips, only: [:new, :edit, :create, :update, :destroy], export: true do
7
- get :download, on: :member, export: :path_only
8
- patch :add_to_playlist, on: :member
9
- patch :remove_from_playlist, on: :member
10
- get :trending, on: :collection
11
- get "/thumbnail/:thumbnail_id", as: :thumbnail, action: :thumbnail, on: :member
12
-
13
- resources :comments, only: [:show, :index], shallow: true, export: true
14
- end
15
-
16
- resources :user_preferences, only: [], export: true do
17
- patch :switch_to_classic_navbar, on: :collection
18
- get :switch_to_beta_navbar, on: :collection, export: false
19
- get "/switch_to_classic/:page", action: :switch_to_classic, on: :collection, export: :path_only
20
- get "/switch_to_beta/:page", action: :switch_to_beta, on: :collection, as: :switch_to_beta_page, export: :path_only
21
- end
22
- end