unpoly-rails 2.0.0 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.

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);