unpoly-rails 2.0.0 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of unpoly-rails might be problematic. Click here for more details.

Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +1 -1
  3. data/README.md +472 -50
  4. data/{dist → assets/unpoly}/unpoly-bootstrap3.css +1 -0
  5. data/assets/unpoly/unpoly-bootstrap3.js +54 -0
  6. data/{dist → assets/unpoly}/unpoly-bootstrap3.min.css +1 -0
  7. data/assets/unpoly/unpoly-bootstrap3.min.js +1 -0
  8. data/{dist → assets/unpoly}/unpoly-bootstrap4.css +1 -0
  9. data/assets/unpoly/unpoly-bootstrap4.js +54 -0
  10. data/{dist → assets/unpoly}/unpoly-bootstrap4.min.css +1 -0
  11. data/assets/unpoly/unpoly-bootstrap4.min.js +1 -0
  12. data/{dist → assets/unpoly}/unpoly-bootstrap5.css +1 -0
  13. data/assets/unpoly/unpoly-bootstrap5.js +56 -0
  14. data/{dist → assets/unpoly}/unpoly-bootstrap5.min.css +1 -0
  15. data/assets/unpoly/unpoly-bootstrap5.min.js +1 -0
  16. data/assets/unpoly/unpoly-migrate.js +1281 -0
  17. data/assets/unpoly/unpoly-migrate.min.js +1 -0
  18. data/{dist → assets/unpoly}/unpoly.css +23 -6
  19. data/assets/unpoly/unpoly.es5.js +23195 -0
  20. data/assets/unpoly/unpoly.es5.min.js +1 -0
  21. data/assets/unpoly/unpoly.js +21457 -0
  22. data/assets/unpoly/unpoly.min.css +10 -0
  23. data/assets/unpoly/unpoly.min.js +1 -0
  24. data/lib/unpoly-rails.rb +12 -12
  25. data/lib/unpoly/rails/controller.rb +1 -1
  26. data/lib/unpoly/rails/engine.rb +13 -20
  27. data/lib/unpoly/rails/request_echo_headers.rb +1 -1
  28. data/lib/unpoly/rails/version.rb +1 -1
  29. metadata +52 -26
  30. data/CHANGELOG.md +0 -2345
  31. data/README_RAILS.md +0 -418
  32. data/dist/unpoly-bootstrap3.js +0 -16
  33. data/dist/unpoly-bootstrap3.min.js +0 -1
  34. data/dist/unpoly-bootstrap4.js +0 -16
  35. data/dist/unpoly-bootstrap4.min.js +0 -1
  36. data/dist/unpoly-bootstrap5.js +0 -14
  37. data/dist/unpoly-bootstrap5.min.js +0 -1
  38. data/dist/unpoly-migrate.js +0 -1306
  39. data/dist/unpoly-migrate.min.js +0 -1
  40. data/dist/unpoly.js +0 -22134
  41. data/dist/unpoly.min.css +0 -1
  42. data/dist/unpoly.min.js +0 -6
  43. data/lib/unpoly/tasks.rb +0 -55
data/README_RAILS.md DELETED
@@ -1,418 +0,0 @@
1
- unpoly-rails: Ruby on Rails bindings for Unpoly
2
- ===============================================
3
-
4
- [Unpoly](https://unpoly.com) is a backend-agnostic [unobtrusive JavaScript](https://en.wikipedia.org/wiki/Unobtrusive_JavaScript) framework. `unpoly-rails` gives a [Ruby on Rails](http://rubyonrails.org/) application some convenience methods to communicate with an Unpoly-enhanced frontend.
5
-
6
- Note that the bindings provided by `unpoly-rails` are entirely optional. You are free to use Unpoly with Rails without the `unpoly-rails` gem.
7
-
8
-
9
- Features
10
- --------
11
-
12
- The methods documented below are available in all controllers, views and helpers.
13
-
14
- ### Detecting a fragment update
15
-
16
- Use `up?` to test whether the current request is a [fragment update](https://unpoly.com/up.link):
17
-
18
- ```ruby
19
- up? # => true or false
20
- ```
21
-
22
- To retrieve the CSS selector that is being [updated](https://unpoly.com/up.link), use `up.target`:
23
-
24
- ```ruby
25
- up.target # => '.content'
26
- ```
27
-
28
- The Unpoly frontend will expect an HTML response containing an element that matches this selector. Your Rails app is free to render a smaller response that only contains HTML matching the targeted selector. You may call `up.target?` to test whether a given CSS selector has been targeted:
29
-
30
- ```ruby
31
- if up.target?('.sidebar')
32
- render('expensive_sidebar_partial')
33
- end
34
- ```
35
-
36
- Fragment updates may target different selectors for successful (HTTP status `200 OK`) and failed (status `4xx` or `5xx`) responses.
37
- Use these methods to inspect the target for failed responses:
38
-
39
- - `up.fail_target`: The CSS selector targeted for a failed response
40
- - `up.fail_target?(selector)`: Whether the given selector is targeted for a failed response
41
- - `up.any_target?(selector)`: Whether the given selector is targeted for either a successful or a failed response
42
-
43
- ### Changing the render target
44
-
45
- The server may instruct the frontend to render a different target by assigning a new CSS selector to the `up.target` property:
46
-
47
- ```ruby
48
- unless signed_in?
49
- up.target = 'body'
50
- render 'sign_in'
51
- end
52
- ```
53
-
54
- The frontend will use the server-provided target for both successful (HTTP status `200 OK`) and failed (status `4xx` or `5xx`) responses.
55
-
56
-
57
- ### Rendering nothing
58
-
59
- Sometimes it's OK to render nothing, e.g. when you know that the current layer is to be closed.
60
-
61
- In this case you may call `up.render_nothing`:
62
-
63
- ```ruby
64
- class NotesController < ApplicationController
65
- def create
66
- @note = Note.new(note_params)
67
- if @note.save
68
- if up.layer.overlay?
69
- up.accept_layer(@note.id)
70
- up.render_nothing
71
- else
72
- redirect_to @note
73
- end
74
- end
75
- end
76
- end
77
- ```
78
-
79
- This will render a 200 OK response with a header `X-Up-Target: none` and an empty body.
80
-
81
- You may render nothing with a different HTTP status by passing a `:status` option:
82
-
83
- ```
84
- up.render_nothing(status: :bad_request)
85
- ```
86
-
87
-
88
- ### Pushing a document title to the client
89
-
90
- To force Unpoly to set a document title when processing the response:
91
-
92
- ```ruby
93
- up.title = 'Title from server'
94
- ```
95
-
96
- This is useful when you skip rendering the `<head>` in an Unpoly request.
97
-
98
- ### Emitting events on the frontend
99
-
100
- You may use `up.emit` to emit an event on the `document` after the
101
- fragment was updated:
102
-
103
- ```ruby
104
- class UsersController < ApplicationController
105
-
106
- def show
107
- @user = User.find(params[:id])
108
- up.emit('user:selected', id: @user.id)
109
- end
110
-
111
- end
112
- ```
113
-
114
- If you wish to emit an event on the current [layer](https://unpoly.com/up.layer)
115
- instead of the `document`, use `up.layer.emit`:
116
-
117
- ```ruby
118
- class UsersController < ApplicationController
119
-
120
- def show
121
- @user = User.find(params[:id])
122
- up.layer.emit('user:selected', id: @user.id)
123
- end
124
-
125
- end
126
- ```
127
-
128
- ### Detecting an Unpoly form validation
129
-
130
- To test whether the current request is a [form validation](https://unpoly.com/input-up-validate):
131
-
132
- ```ruby
133
- up.validate?
134
- ```
135
-
136
- When detecting a validation request, the server is expected to validate (but not save) the form submission and render a new copy of the form with validation errors. A typical saving action should behave like this:
137
-
138
- ```ruby
139
- class UsersController < ApplicationController
140
-
141
- def create
142
- user_params = params[:user].permit(:email, :password)
143
- @user = User.new(user_params)
144
- if up.validate?
145
- @user.valid? # run validations, but don't save to the database
146
- render 'form' # render form with error messages
147
- elsif @user.save?
148
- sign_in @user
149
- else
150
- render 'form', status: :bad_request
151
- end
152
- end
153
-
154
- end
155
- ```
156
-
157
- ### Detecting a fragment reload
158
-
159
- To test whether the current request was made to [reload](https://unpoly.com/up.reload) or [poll](https://unpoly.com/up-poll) a fragment:
160
-
161
- ```ruby
162
- up.reload?
163
- ```
164
-
165
- You also retrieve the time when the fragment being reloaded was previously inserted into the DOM:
166
-
167
- ```ruby
168
- up.reload_from_time # returns a Time object
169
- ```
170
-
171
- The server can compare the time from the request with the time of the last data update.
172
- If no more recent data is available, the server can [render nothing](/X-Up-Target):
173
-
174
- ```ruby
175
- class MessagesController < ApplicationController
176
-
177
- def index
178
- if up.reload_from_time == current_user.last_message_at
179
- up.render_nothing
180
- else
181
- @messages = current_user.messages.order(time: :desc).to_a
182
- render 'index'
183
- end
184
- end
185
-
186
- end
187
- ```
188
-
189
- Only rendering when needed saves <b>CPU time</b> on your server, which spends most of its response time rendering HTML.
190
-
191
- This also reduces the <b>bandwidth cost</b> for a request/response exchange to **~1 KB**.
192
-
193
-
194
- ### Working with context
195
-
196
- Calling `up.context` will return the [context](https://unpoly.com/up.context) object of the targeted layer.
197
-
198
- The context is a JSON object shared between the frontend and the server.
199
- It persists for a series of Unpoly navigation, but is cleared when the user makes a full page load.
200
- Different Unpoly [layers](https://unpoly.com/up.layer) will usually have separate context objects,
201
- although layers may choose to share their context scope.
202
-
203
- You may read and change the context object. Changes will be sent to the frontend with your response.
204
-
205
- ```ruby
206
- class GamesController < ApplicationController
207
-
208
- def restart
209
- up.context[:lives] = 3
210
- render 'stage1'
211
- end
212
-
213
- end
214
- ```
215
-
216
- Keys can be accessed as either strings or symbols:
217
-
218
- ```ruby
219
- puts "You have " + up.layer.context[:lives] + " lives left"
220
- puts "You have " + up.layer.context['lives'] + " lives left"
221
- ````
222
-
223
- You may delete a key from the frontend by calling `up.context.delete`:
224
-
225
- ```ruby
226
- up.context.delete(:foo)
227
- ````
228
-
229
- You may replace the entire context by calling `up.context.replace`:
230
-
231
- ```
232
- context_from_file = JSON.parse(File.read('context.json))
233
- up.context.replace(context_from_file)
234
- ```
235
-
236
- `up.context` is an alias for `up.layer.context`.
237
-
238
-
239
- ### Accessing the targeted layer
240
-
241
- Use the methods below to interact with the [layer](/up.layer) of the fragment being targeted.
242
-
243
- Note that fragment updates may target different layers for successful (HTTP status `200 OK`) and failed (status `4xx` or `5xx`) responses.
244
-
245
- #### `up.layer.mode`
246
-
247
- Returns the [mode](https://unpoly.com/up.layer.mode) of the targeted layer (e.g. `"root"` or `"modal"`).
248
-
249
- #### `up.layer.root?`
250
-
251
- Returns whether the targeted layer is the root layer.
252
-
253
- #### `up.layer.overlay?`
254
-
255
- Returns whether the targeted layer is an overlay (not the root layer).
256
-
257
- #### `up.layer.context`
258
-
259
- Returns the [context](https://unpoly.com/up.context) object of the targeted layer.
260
- See documentation for `up.context`, which is an alias for `up.layer.context`.
261
-
262
- #### `up.layer.accept(value)`
263
-
264
- [Accepts](https://unpoly.com/up.layer.accept) the current overlay.
265
-
266
- Does nothing if the root layer is targeted.
267
-
268
- Note that Rails expects every controller action to render or redirect.
269
- Your action should either call `up.render_nothing` or respond with `text/html` content matching the requested target.
270
-
271
- #### `up.layer.dismiss(value)`
272
-
273
- [Dismisses](https://unpoly.com/up.layer.dismisses) the current overlay.
274
-
275
- Does nothing if the root layer is targeted.
276
-
277
- Note that Rails expects every controller action to render or redirect.
278
- Your action should either call `up.render_nothing` or respond with `text/html` content matching the requested target.
279
-
280
- #### `up.layer.emit(type, options)`
281
-
282
- [Emits an event](https://unpoly.com/up.layer.emit) on the targeted layer.
283
-
284
- #### `up.fail_layer.mode`
285
-
286
- Returns the [mode](https://unpoly.com/up.layer.mode) of the layer targeted for a failed response.
287
-
288
- #### `up.fail_layer.root?`
289
-
290
- Returns whether the layer targeted for a failed response is the root layer.
291
-
292
- #### `up.fail_layer.overlay?`
293
-
294
- Returns whether the layer targeted for a failed response is an overlay.
295
-
296
- #### `up.fail_layer.context`
297
-
298
- Returns the [context](https://unpoly.com/up.context) object of the layer targeted for a failed response.
299
-
300
-
301
- ### Managing the client-side cache
302
-
303
- The Unpoly frontend caches server responses for a few minutes, making requests to these URLs return instantly.
304
- Only `GET` requests are cached. The *entire* cache is cleared after every non-`GET` request (like `POST` or `PUT`).
305
-
306
- The server may override these defaults. For instance, the server can clear Unpoly's client-side response cache, even for `GET` requests:
307
-
308
- ```ruby
309
- up.cache.clear
310
- ```
311
-
312
- You may also clear a single page:
313
-
314
- ```ruby
315
- up.cache.clear('/notes/1034')
316
- ```
317
-
318
- You may also clear all entries matching a URL pattern:
319
-
320
- ```ruby
321
- up.cache.clear('/notes/*')
322
- ```
323
-
324
- You may also prevent cache clearing for an unsafe request:
325
-
326
- ```ruby
327
- up.cache.keep
328
- ```
329
-
330
- Here is an longer example where the server uses careful cache management to keep as much of the client-side cache as possible:
331
-
332
- ```ruby
333
- def NotesController < ApplicationController
334
-
335
- def create
336
- @note = Note.create!(params[:note].permit(...))
337
- if @note.save
338
- up.cache.clear('/notes/*') # Only clear affected entries
339
- redirect_to(@note)
340
- else
341
- up.cache.keep # Keep the cache because we haven't saved
342
- render 'new'
343
- end
344
- end
345
- ...
346
- end
347
- ```
348
-
349
-
350
- ### Preserving Unpoly-related request information through redirects
351
-
352
- `unpoly-rails` patches [`redirect_to`](https://api.rubyonrails.org/classes/ActionController/Redirecting.html#method-i-redirect_to)
353
- so Unpoly-related request information (like the CSS selector being targeted for a fragment
354
- update) will be preserved for the action you redirect to.
355
-
356
-
357
- ### Automatic redirect detection
358
-
359
- `unpoly-rails` installs a [`before_action`](https://api.rubyonrails.org/classes/AbstractController/Callbacks/ClassMethods.html#method-i-before_action) into all controllers which echoes the request's URL as a response header `X-Up-Location` and the request's
360
- HTTP method as `X-Up-Method`.
361
-
362
-
363
- ### Automatic method detection for initial page load
364
-
365
- `unpoly-rails` sets an `_up_method` cookie that Unpoly needs to detect the request method for the initial page load.
366
-
367
- If the initial page was loaded with a non-`GET` HTTP method, Unpoly will fall back to full page loads for all actions that require `pushState`.
368
-
369
- The reason for this is that some browsers remember the method of the initial page load and don't let the application change it, even with `pushState`. Thus, when the user reloads the page much later, an affected browser might request a `POST`, `PUT`, etc. instead of the correct method.
370
-
371
-
372
- What you still need to do manually
373
- ----------------------------------
374
-
375
- ### Failed form submissions must return a non-200 status code
376
-
377
- Unpoly lets you submit forms via AJAX by using the [`form[up-follow]`](https://unpoly.com/form-up-submit) selector or [`up.submit()`](https://unpoly.com/up.submit) function.
378
-
379
- For Unpoly to be able to detect a failed form submission,
380
- the form must be re-rendered with a non-200 HTTP status code.
381
- We recommend to use either 400 (bad request) or 422 (unprocessable entity).
382
-
383
- To do so in Rails, pass a [`:status` option to `render`](http://guides.rubyonrails.org/layouts_and_rendering.html#the-status-option):
384
-
385
- ```ruby
386
- class UsersController < ApplicationController
387
-
388
- def create
389
- user_params = params[:user].permit(:email, :password)
390
- @user = User.new(user_params)
391
- if @user.save?
392
- sign_in @user
393
- else
394
- render 'form', status: :bad_request
395
- end
396
- end
397
-
398
- end
399
- ```
400
-
401
- Development
402
- -----------
403
-
404
- ### Before you make a PR
405
-
406
- Before you create a pull request, please have some discussion about the proposed change by [opening an issue on GitHub](https://github.com/unpoly/unpoly/issues/new).
407
-
408
- ### Running tests
409
-
410
- - Install Ruby 2.3.8
411
- - Install Bundler by running `gem install bundler`
412
- - `cd` into `spec_app`
413
- - Install dependencies by running `bundle install`
414
- - Run `rspec`
415
-
416
- ### Making a new release
417
-
418
- New versions of `unpoly-rails` are released as part of the [Unpoly release process](https://github.com/unpoly/unpoly/blob/master/README.md#making-a-new-release), which also feeds other package managers like Bower or npm.
@@ -1,16 +0,0 @@
1
- (function() {
2
- up.feedback.config.currentClasses.push('active');
3
-
4
- up.feedback.config.navSelectors.push('.nav', '.navbar');
5
-
6
- up.form.config.validateTargets.unshift('.form-group:has(:origin)');
7
-
8
- up.viewport.config.fixedTop.push('.navbar-fixed-top');
9
-
10
- up.viewport.config.fixedBottom.push('.navbar-fixed-bottom');
11
-
12
- up.viewport.config.anchoredRight.push('.navbar-fixed-top', '.navbar-fixed-bottom');
13
-
14
- up.fragment.config.badTargetClasses.push('row', /^col(-xs|-sm|-md|-lg)?(-\d+)?$/);
15
-
16
- }).call(this);
@@ -1 +0,0 @@
1
- (function(){up.feedback.config.currentClasses.push("active"),up.feedback.config.navSelectors.push(".nav",".navbar"),up.form.config.validateTargets.unshift(".form-group:has(:origin)"),up.viewport.config.fixedTop.push(".navbar-fixed-top"),up.viewport.config.fixedBottom.push(".navbar-fixed-bottom"),up.viewport.config.anchoredRight.push(".navbar-fixed-top",".navbar-fixed-bottom"),up.fragment.config.badTargetClasses.push("row",/^col(-xs|-sm|-md|-lg)?(-\d+)?$/)}).call(this);
@@ -1,16 +0,0 @@
1
- (function() {
2
- up.feedback.config.currentClasses.push('active');
3
-
4
- up.feedback.config.navSelectors.push('.nav', '.navbar');
5
-
6
- up.form.config.validateTargets.unshift('.form-group:has(:origin)');
7
-
8
- up.viewport.config.fixedTop.push('.navbar.fixed-top');
9
-
10
- up.viewport.config.fixedBottom.push('.navbar.fixed-bottom');
11
-
12
- up.viewport.config.anchoredRight.push('.navbar.fixed-top', '.navbar.fixed-bottom');
13
-
14
- up.fragment.config.badTargetClasses.push('row', /^col(-xs|-sm|-md|-lg|-xl)?(-\d+)?$/, /^[mp][tblrxy]?-\d+$/);
15
-
16
- }).call(this);