rails_redhot 0.0.2 → 0.1.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.
- checksums.yaml +4 -4
- data/README.md +99 -31
- data/lib/rails_redhot/version.rb +1 -1
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5be8aff1e9314532378f476e76fe310b84bfe386abe0ba18c33ec60820696d24
|
4
|
+
data.tar.gz: f77470f8cec6b501c56fb0102e1b63242b0a11a4c453d4bbe3b3068b148b88fe
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: adbb2a15f3bcffe7b910b05217d5e564125915bd39710347b527a863462fb7bef50951358d0b2d31829994410abca865f88f183abe09e09e0aef8be56956a5bf
|
7
|
+
data.tar.gz: 922d4eac6e294a8f25ac027eca82c457115884758fc785289c79867785618aa0f7a788975e5f66fcb4139bfd819cca39b4b263d6d7d8df989a6cdc03bec8f97d
|
data/README.md
CHANGED
@@ -9,13 +9,14 @@ Or when building a search page for a webshop. Whenever the user selects a catego
|
|
9
9
|
or price range to filter on this can be an action for the redux store. If the user
|
10
10
|
hits the back button the last action can be deleted and the current state
|
11
11
|
regenerated by reducing all remaining actions. The user only sees the last filter
|
12
|
-
being reverted to what it was before.
|
12
|
+
being reverted to what it was before.
|
13
|
+
|
13
14
|
Sometimes the actions of the user in the frontend should be sent to a backend
|
14
15
|
application. For instance when actions of multiple users should be kept in-sync.
|
15
16
|
Often command-query-responsibility-separation (CQRS) is used for this purpose.
|
16
17
|
These solutions can become very complex
|
17
|
-
([example](https://medium.com/resolvejs/resolve-redux-backend-ebcfc79bbbea)
|
18
|
-
scroll down a bit).
|
18
|
+
([example](https://medium.com/resolvejs/resolve-redux-backend-ebcfc79bbbea),
|
19
|
+
scroll down a bit for a full example).
|
19
20
|
|
20
21
|
The Hotwire (Html Over The Wire) approach does an excellent job of removing the need
|
21
22
|
to build single page apps. Hotwire will be the
|
@@ -28,20 +29,22 @@ is still very useful for this purpose.
|
|
28
29
|
|
29
30
|
This gem aims to combine html-over-the-wire approach with the redux pattern to
|
30
31
|
radically reduce complexity of the overall application.
|
31
|
-
(At least when compared to for instance react+cqrs.)
|
32
|
+
(At least when compared to for instance react+cqrs application stacks.)
|
32
33
|
Only four components are required:
|
33
34
|
|
34
35
|
1. Views, normal rails views rendering the current state and delivered as turbo frames
|
35
|
-
2. Actions, just
|
36
|
+
2. Actions, just submit buttons that send a request to the backend handled by a controller
|
36
37
|
3. Store, keeping the list of actions and current state, managed by this gem and stored
|
37
38
|
in an activerecord model
|
38
|
-
4. Reducers, a set of functions (provided by you) that translate actions to changes in
|
39
|
+
4. Reducers, a set of functions (provided by you) that translate actions to changes in
|
40
|
+
state. The state can be used again in step 1
|
39
41
|
|
40
42
|
Common actions (undo, redo, flatten actions to initial state) are provided by this gem.
|
41
43
|
Combined with turbo frames for rendering partial page updates this makes it easy to
|
42
44
|
create a very smooth user experience.
|
43
45
|
|
44
46
|
## Usage
|
47
|
+
### Model
|
45
48
|
Create a migration to add a 'text' type attribute to a model that should have a redux store.
|
46
49
|
In the model add an `acts_as_redux` line, specifying the name of the text attribute.
|
47
50
|
Add a private method holding all your reducer functions.
|
@@ -49,40 +52,102 @@ See [this example](test/dummy/app/models/foobar.rb).
|
|
49
52
|
Note that all reducer functions must return the state object (a Hash).
|
50
53
|
|
51
54
|
```ruby
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
55
|
+
class Foobar < ApplicationRecord
|
56
|
+
include RailsRedhot::ActsAsRedux
|
57
|
+
|
58
|
+
acts_as_redux :my_redux
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def my_redux_reducers
|
63
|
+
->(state, action) {
|
64
|
+
case action[:type]
|
65
|
+
when :add
|
66
|
+
state[:total] += 1
|
67
|
+
when :remove
|
68
|
+
state[:total] -= 1
|
69
|
+
end
|
70
|
+
state
|
71
|
+
},
|
65
72
|
end
|
66
|
-
state
|
67
|
-
},
|
68
73
|
end
|
69
74
|
```
|
70
75
|
|
71
76
|
Or specify your own reducer method:
|
72
77
|
|
73
78
|
```ruby
|
74
|
-
acts_as_redux :my_redux, reducers: :
|
79
|
+
acts_as_redux :my_redux, reducers: :my_list_of_reducers
|
75
80
|
|
76
|
-
def
|
81
|
+
def my_list_of_reducers
|
77
82
|
# ...
|
78
83
|
```
|
79
84
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
85
|
+
### Undo/redo
|
86
|
+
Every instance of the model now has access to several methods.
|
87
|
+
For undoing actions there are: `undo?`, `undo_action` and `undo!`,
|
88
|
+
which you might use in a view like this:
|
89
|
+
|
90
|
+
```ruby
|
91
|
+
<%- if foobar.undo? %>
|
92
|
+
<%= form_with(model: foobar, url: update_action_foobar_path(foobar), method: :put) do |form| %>
|
93
|
+
<%= form.hidden_field :action, value: :undo %>
|
94
|
+
<%= form.submit "Undo: #{foobar.undo_action['type']}" %>
|
95
|
+
<% end %>
|
96
|
+
<% end %>
|
97
|
+
```
|
98
|
+
In the controller action use the `undo!` method to perform the action.
|
99
|
+
For redoing actions the similar methods `redo?`, `redo_action` and `redo!` are available.
|
100
|
+
|
101
|
+
### Flatten
|
102
|
+
You can 'save' the current state. Essentially this flattens the list of actions to the initial state.
|
103
|
+
Methods `flatten?` and `flatten!` can be used in a view and controller:
|
104
|
+
|
105
|
+
```ruby
|
106
|
+
<%- if foobar.flatten? %>
|
107
|
+
<%= form_with(model: foobar, url: update_action_foobar_path(foobar), method: :put) do |form| %>
|
108
|
+
<%= form.hidden_field :action, value: :flatten %>
|
109
|
+
<%= form.submit "Save changes" %>
|
110
|
+
<% end %>
|
111
|
+
<% end %>
|
112
|
+
```
|
113
|
+
|
114
|
+
### Sequence ID
|
115
|
+
As a convenience a sequence ID id available which should always return a unique id
|
116
|
+
(within the context of the model instance). To get the next sequence id use `next_seq_id`,
|
117
|
+
to get the current sequence value use `seq_id`.
|
118
|
+
You could use a sequence in a reducer function to make sure every added item is assigned a unique id.
|
119
|
+
|
120
|
+
### Dispatch actions and view state
|
121
|
+
To add an action to the store you can use the `dispatch!` method, passing a hash with the details of the action.
|
122
|
+
What the content of that hash should be is up to you.
|
123
|
+
As long as your reducer fuctions can handle the action anything is possible.
|
124
|
+
|
125
|
+
Finally to get the current state the `view_state` method is available.
|
126
|
+
In a view it can be used like so:
|
127
|
+
|
128
|
+
```ruby
|
129
|
+
<p>
|
130
|
+
There are <%= foobar.view_state['total'] %> items
|
131
|
+
</p>
|
132
|
+
|
133
|
+
<%- foobar.view_state['items'].each do |item| %>
|
134
|
+
<p>
|
135
|
+
<%= CGI.unescape(item['value']) %>
|
136
|
+
</p>
|
137
|
+
<% end %>
|
138
|
+
```
|
139
|
+
|
140
|
+
The `view_state` method returns a Hash. What the content of this hash looks like depends
|
141
|
+
on the reducer functions you have implemented.
|
142
|
+
|
143
|
+
For a full working example see the demo applications [view](test/dummy/app/views/foobars/_editor.html.erb)
|
144
|
+
and [controller](test/dummy/app/controllers/foobars_controller.rb).
|
145
|
+
|
146
|
+
## Security
|
147
|
+
Care must be taken to not introduce any vulnerabilities.
|
148
|
+
When passing values from the request to the reducer functions treat any string or complex
|
149
|
+
values as potential candidates for SQL injection. Either sanitize the value or `CGI.escape`
|
150
|
+
a string before adding it to the redux store.
|
86
151
|
|
87
152
|
## Installation
|
88
153
|
Add this line to your application's Gemfile:
|
@@ -113,14 +178,14 @@ rails db:setup
|
|
113
178
|
rails server
|
114
179
|
```
|
115
180
|
|
116
|
-
|
181
|
+
Then open the [application](http://localhost:3000/foobars).
|
117
182
|
Click on 'New foobar', 'Add a new foobar' and 'Edit this foobar'.
|
118
183
|
|
119
184
|
## Test
|
120
185
|
Run:
|
121
186
|
|
122
187
|
```bash
|
123
|
-
rails test/dummy/test
|
188
|
+
rails test test/dummy/test
|
124
189
|
```
|
125
190
|
|
126
191
|
## License
|
@@ -134,6 +199,9 @@ The gem is available as open source under the terms of the [MIT License](https:/
|
|
134
199
|
If the list of actions to process is large this would become slow.
|
135
200
|
One would need add 'savepoints' that regularly save the state and rebuild
|
136
201
|
the current state from that point forward
|
202
|
+
- Stricly speaking, hotwire is not needed for this gem to work. Just using
|
203
|
+
plain old rails views and controllers is fine. Hotwire certainly makes
|
204
|
+
an application using this gem a lot faster
|
137
205
|
- No checking on the size of the text attribute used for the store is done
|
138
206
|
- Currently only one redux store can be added to a model
|
139
207
|
- Redux store code inspired by:
|
data/lib/rails_redhot/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rails_redhot
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ivo Herweijer
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-12-
|
11
|
+
date: 2021-12-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 7.0.0
|
19
|
+
version: 7.0.0
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 7.0.0
|
26
|
+
version: 7.0.0
|
27
27
|
description: REDux pattern for HOTwire == Redhot
|
28
28
|
email:
|
29
29
|
- info@edwhs.nl
|