From f4c2e383df46f67b1c2ca87b20babe3ab7ab6b52 Mon Sep 17 00:00:00 2001 From: leastbad Date: Fri, 28 Feb 2020 10:41:29 +0000 Subject: [PATCH] GitBook: [master] 4 pages and 5 assets modified --- .gitbook/assets/alien_science.svg | 1 + .gitbook/assets/master_plan.svg | 1 + .gitbook/assets/special_event.svg | 1 + .gitbook/assets/success_factors.svg | 1 + .gitbook/assets/super_woman.svg | 1 + README.md | 4 +-- SUMMARY.md | 3 +- advanced-usage.md | 50 +++++++++++++++++++++++++++++ reference.md | 6 ++++ 9 files changed, 65 insertions(+), 3 deletions(-) create mode 100644 .gitbook/assets/alien_science.svg create mode 100644 .gitbook/assets/master_plan.svg create mode 100644 .gitbook/assets/special_event.svg create mode 100644 .gitbook/assets/success_factors.svg create mode 100644 .gitbook/assets/super_woman.svg create mode 100644 advanced-usage.md diff --git a/.gitbook/assets/alien_science.svg b/.gitbook/assets/alien_science.svg new file mode 100644 index 0000000..dc0d89c --- /dev/null +++ b/.gitbook/assets/alien_science.svg @@ -0,0 +1 @@ +alien science \ No newline at end of file diff --git a/.gitbook/assets/master_plan.svg b/.gitbook/assets/master_plan.svg new file mode 100644 index 0000000..8b96be3 --- /dev/null +++ b/.gitbook/assets/master_plan.svg @@ -0,0 +1 @@ +master_plan \ No newline at end of file diff --git a/.gitbook/assets/special_event.svg b/.gitbook/assets/special_event.svg new file mode 100644 index 0000000..2ce78de --- /dev/null +++ b/.gitbook/assets/special_event.svg @@ -0,0 +1 @@ +special_event \ No newline at end of file diff --git a/.gitbook/assets/success_factors.svg b/.gitbook/assets/success_factors.svg new file mode 100644 index 0000000..3596866 --- /dev/null +++ b/.gitbook/assets/success_factors.svg @@ -0,0 +1 @@ +success_factors \ No newline at end of file diff --git a/.gitbook/assets/super_woman.svg b/.gitbook/assets/super_woman.svg new file mode 100644 index 0000000..1ed569f --- /dev/null +++ b/.gitbook/assets/super_woman.svg @@ -0,0 +1 @@ +super woman \ No newline at end of file diff --git a/README.md b/README.md index b65470d..7190975 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ When a model validation error prevents an update from succeeding, Optimism build * [x] Optional support for emitting DOM events * [x] Highly configurable via an optional initializer file * [x] CSS framework agnostic with Bootstrap and vanilla samples provided -* [x] Lightweight, coming in at roughly 100 LOC +* [x] Lightweight, coming in at ~100 LOC ## Try it now @@ -46,5 +46,5 @@ There's a live demo that you can try right now at [https://optimism-demo.herokua Even better, the source code for the demo is [available on Github](https://github.com/leastbad/optimism). The project README lists every step required to build the demo application from scratch in about five minutes. -Excited? Great! Let's [setup Optimism](https://optimism.leastbad.com/setup) in your Rails app now. +Excited? Great! Let's [setup Optimism](https://optimism.leastbad.com/setup) in your Rails application now. diff --git a/SUMMARY.md b/SUMMARY.md index 7e9fdd5..e8ae2fc 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -1,8 +1,9 @@ # Table of contents -* [Welcome](README.md) +* [Optimism](README.md) * [Setup](setup.md) * [Quick Start](quick-start.md) * [Typical Usage](typical-usage.md) * [Reference](reference.md) +* [Advanced Usage](advanced-usage.md) diff --git a/advanced-usage.md b/advanced-usage.md new file mode 100644 index 0000000..bc0f326 --- /dev/null +++ b/advanced-usage.md @@ -0,0 +1,50 @@ +# Advanced Usage + +Until now, the majority of this documentation has focused on the primary out-of-the-box functionality of Rails remote forms, which are just like 1996 forms except they are submitted using 1999's XMLHttpRequest object. This page deals with contemporary interfaces, tilting towards the future. + +Generally speaking, traditional forms are a way to submit a bucket of associated key/value pairs intended to update a single instance of a resource. With the advent of JS-powered interfaces, there are now many patterns which require re-thinking how to update individual attributes while ensuring a consistent state between the client and server. Unfortunately, the aging HTML form is poorly equipped to deal with anything that doesn't conform to a dated, white bread possibility space. + +Optimism is a server-side solution. It would be impractical to try and provide client-side solutions to these problems; even if we succeed in covering every framework and design approach, we don't want to limit creative freedom or made integration difficult just because we didn't anticipate something. + +That said, we believe Optimism provides a lot of flexibility for people who can build or adapt their client-side solutions to work with our simple API; in many cases, it just comes down to sending less data. When combined with other tools, comprehensive solutions are possible with very little custom code. + +## Reactive validations + +Whether hotter/colder updates about the availability of our desired username or having the background color of a text input change color when we type too many characters, people have come to expect real-time feedback from input elements. If you have to submit a form to find out that your password needs to have special characters in it, well, that page sucks and many users are sophisticated enough to feel legitimate frustration when developers get this wrong. + +The key to real-time validation updates with Rails remote forms is that you can submit to the same resource end-point with the same form structure, just constrained to only the current attribute. That means your client code has to be able to pick up the current form's HTTP **\_method** and **authenticity\_token** fields and pack them into a POST along with the desired attribute, making sure to grab the full Rails name key for the attribute. This is especially vital when dealing with nested forms, for example Comments embedded in a Post might look like '**post\[comments\_attributes\]\[0\]\[body\]**'. You'll also need to remember to **set the X-Requested-With header to 'XMLHttpRequest'**. + +In theory, if you follow the thread of the previous paragraph Optimism should "just work" because the post\_params will only have the attribute currently being modified in it. However, if your application works differently, the most important thing to remember is that the 2nd parameter to the [broadcast\_errors](https://optimism.leastbad.com/reference#broadcast_errors-model-attributes) function can also be a single String or Symbol. This means that you can use Optimism regardless of whether there's a form on the active page, even if it doesn't look like a form. You could give live feedback for a typeahead search in a header that uses an input element outside of the context of a form. + +Optimism works by looking for elements with IDs that match expected patterns. If you're only emitting events then even that constraint is off the table. Advanced users can think of Optimism as a message bus for communicating validation errors in real-time over websockets, which is very liberating. + +![](.gitbook/assets/success_factors.svg) + +## In-line edit UIs + +After the advances in UI design advanced by thinkers such as Larry Tesler and Jef Raskin during the 1980s led to concepts like [modeless computing](https://en.wikipedia.org/wiki/Mode_%28user_interface%29), it could be argued that the humble HTML form was a primitive modeless concept designed to work over a stateless protocol. + +Then REST interfaces came along and brought the computing world right back to the 1970s, with distinct modes for listing, viewing and editing data. While REST did bring a desirable predictability to API discoverability and URL conventions, it is fundamentally inflexible and has little provision for real-time dynamic interfaces with bi-directional data binding. That leaves us to figure out how to find a general solution to editing data without leaving the view \(show\) state. Unlike reactive validations, where the server is a single source of truth, actually changing a single data value from an arbitrary place in your application is a surprisingly difficult challenge, before even considering all of the different client libraries and design approaches one might take. + +The two hardest problems confronting any Rails developer, even without Optimism's help, are syncronization and partial updates. + +Syncronization is the easiest to explain and the hardest to solve. Simply: what if the value of data changes on the server after the page has been rendered on client browser? Libraries like [StimulusReflex](https://github.com/hopsoft/stimulus_reflex) go to great pains to not replace the contents of an input element while you're typing into it. Simply put, there's an opinionated decision made that what you're typing should be the source of truth until that element no longer has focus. You then have to figure out how to decide which value lives: the one on the server that the user never saw, or this new input from the user? There is no right answer, and usually the last update wins. Interfaces such as Optimism and libraries like StimulusReflex give us the opportunity to consider a hybrid approach where the form could update to show that data has changed on the server, either showing the new server value alongside the input element, or even locking the input element entirely. + +Partial updates is an umbrella concept for a group of related concerns that emerge when updating a subset of attributes on a model that has rules in place covering many attributes. Some of those attributes might not be included in the subset you're updating. For example, if you're trying to provide an in-line edit UI for a model that has multiple required attributes, when you enter data for the first attribute the model will not be created because it fails validations. This raises the question of where those individual updates go before you have enough data captured to create a valid instance of the model. Rails does not address this gracefully out of the box, beyond implying that a new model instance should be created in one shot while some additional flexibility is possible with updates. + +It's impossible to be half-pregnant. In Rails, it's impossible to half-save a new record. + +For example, this means that it's really tricky to implement a git-style commit concept, where you might make multiple changes to a dataset before ultimately commiting it to a permanent datastore. This was less practical in the era of stateless HTTP page reloads, but now that we have websockets and powerful UI libraries, it sucks that we don't have better answers to these patterns. + +Another casualty is the prospect of undo/redo capable UIs. Today, undo/redo is generally confined to text editing operations, while applications like Photoshop have had powerful history navigators for decades. Frankly, it's upsetting that so much energy goes into making React useful when we still haven't solved making undo work across conceptual domains on the web. + +Partial updates aren't a Rails-specific problem, but Rails validation infrastucture does make this design goal harder to achieve. All general schemes have constraints and limitations, and if DHH had made different decisions, we would have different problems to deal with. + +There is also progress in the ActiveRecord API. You can now query individual attributes to see if they are valid or dirty \(changed\). These building blocks offer paths to more comprehensive solutions in the future. + +What Optimism can offer today is a bridge while other aspects of this puzzle are figured out for the next generation of web developers. It has the ability to add a CSS class representing invalid state to the form. It can even be [configured](https://optimism.leastbad.com/reference#initializer) to disable the Submit button if the model is in an invalid state. While not a complete solution, we hope this proves a useful part of the solution. + +![](.gitbook/assets/super_woman.svg) + +## + diff --git a/reference.md b/reference.md index 6fd44a9..025f18b 100644 --- a/reference.md +++ b/reference.md @@ -84,6 +84,8 @@ Returns the id required for a container to receive validation error text. Use it +![](.gitbook/assets/master_plan.svg) + ## Initializer Optimism is configurable via an optional initializer file. As with all initializers, changes only take effect after your Rails server has been restarted. Here is a sample initializer file that contains all of the default values for the configuration of the library. All changes apply globally to all instances of Optimism. @@ -137,6 +139,8 @@ end If you set the `emit_events` property to true in your initializer, Optimism will emit DOM events in response to validation errors. This can happen in addition to or instead of CSS and text updates. This is a great alternative for complicated integrations where you have legacy components which need to be notified of error conditions on the backend. +In practical terms, DOM events give you tooling options and creative flexibility that are difficult to achieve with textual error messages and CSS error classes. It's simply a fact that no library can anticipate every design pattern or UI innovation. Today you might connect DOM events to a [toast notification library](https://www.jqueryscript.net/blog/Best-Toast-Notification-jQuery-Plugins.html#vanilla), but tomorrow there could be a mass proliferation of embedded ocular computers with sub-vocalization control interfaces, and we aren't going to tell you how those devices should punish users for bad input. + ### Form-level events Event: **optimism:form:invalid** @@ -157,3 +161,5 @@ Detail: resource, attribute One of these events will fire **for each attribute**, depending on whether that attribute is valid. Resource is the pluralized class name of the Active Record model, eg. `posts`. Attribute is hopefully self-explanatory. Text is the text content of the validation error message. +![](.gitbook/assets/alien_science.svg) +