svelte-on-rails 5.3.1 → 6.0.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 +63 -49
- data/lib/svelte-on-rails.rb +1 -0
- data/lib/svelte_on_rails/action_cable.rb +1 -1
- data/lib/svelte_on_rails/active_record_extensions.rb +26 -22
- data/lib/svelte_on_rails/lib/to_svelte.rb +190 -0
- data/lib/svelte_on_rails/lib/utils.rb +0 -126
- data/lib/svelte_on_rails/lib/view_helper_support.rb +7 -1
- data/lib/svelte_on_rails/railtie.rb +8 -0
- data/lib/svelte_on_rails/renderer/render.js +2 -2
- data/lib/svelte_on_rails/turbo_stream.rb +1 -1
- data/templates/all_features_test/app/controllers/svelte_on_rails_hello_world_controller.rb +0 -4
- data/templates/all_features_test/app/frontend/initializers/actionCable.js +2 -1
- metadata +2 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 72ff2251a05680fdb51fa556c72aaba218728a0040265412544d838ef7a4b4e7
|
4
|
+
data.tar.gz: 394c75169ba815b224e74f5b4c3e2675f50845505f4e00c52bdecf363b9db4ba
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cfbbe11843b3b00a104bba37d942c98f5e49aca735f0b933475a3ee77b495418758eb83638b073dd7ed5e866a32bacc4c434e6daaa33e7b98303aa8731093bfe
|
7
|
+
data.tar.gz: a228c78ccf69847ff2f61d360734af6d1e7cb912b3928d6af056585fa1cabc0d121405c5d7b9099b659d15143a1771937e6d3745aa80bfd8a39d73e0fea66b0a
|
data/README.md
CHANGED
@@ -5,20 +5,11 @@
|
|
5
5
|
|
6
6
|
---
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
Guided by our Principles:
|
11
|
-
|
12
|
-
- **Minimal JavaScript but Reactive Power**
|
13
|
-
- **Beautiful Code, More Joy, Better Results**
|
14
|
-
- **Convention over Configuration**
|
15
|
-
|
16
|
-
`svelte-on-rails` completes [DHH's vision](https://rubyonrails.org/2021/12/15/Rails-7-fulfilling-a-vision)
|
17
|
-
for modern front-end demands.
|
8
|
+
Realizing [DHH's vision](https://rubyonrails.org/2021/12/15/Rails-7-fulfilling-a-vision) with modern front-end technologies.
|
18
9
|
|
19
10
|
# Why Integrate Svelte?
|
20
11
|
|
21
|
-
Svelte offers the simplest and most elegant
|
12
|
+
Svelte offers the simplest and most elegant soulution to building reactive, high-performance front-end components.
|
22
13
|
|
23
14
|
- **Seamless Integration**
|
24
15
|
- Works flawlessly with Hotwired/Turbo
|
@@ -311,13 +302,18 @@ But, in normal cases it should not be neccessary testing ssr explicitly.
|
|
311
302
|
|
312
303
|
## ActiveRecord helpers
|
313
304
|
|
314
|
-
Adds the `#
|
305
|
+
Adds the `#to_svelte` helper to your models, example:
|
315
306
|
|
316
307
|
```ruby
|
317
|
-
@book.
|
308
|
+
@book.to_svelte(
|
318
309
|
:name,
|
319
310
|
:calculation_method,
|
320
|
-
author: [:name]
|
311
|
+
author: [:name],
|
312
|
+
editions: [
|
313
|
+
:date,
|
314
|
+
offset: 2,
|
315
|
+
limit: 1
|
316
|
+
]
|
321
317
|
)
|
322
318
|
```
|
323
319
|
|
@@ -331,6 +327,11 @@ would result in something like this:
|
|
331
327
|
"author" => {
|
332
328
|
"name" => "Michael Hartl"
|
333
329
|
},
|
330
|
+
"editions" => [
|
331
|
+
{
|
332
|
+
date: "2025-02-03"
|
333
|
+
}
|
334
|
+
]
|
334
335
|
},
|
335
336
|
"book_labels" => {
|
336
337
|
"name" => "Name", # translated by human_attribute_name..
|
@@ -339,15 +340,35 @@ would result in something like this:
|
|
339
340
|
},
|
340
341
|
"author_labels": {
|
341
342
|
"name" => "Name"
|
343
|
+
},
|
344
|
+
"edition_labels" => {
|
345
|
+
"date" => "Date"
|
342
346
|
}
|
343
347
|
}
|
344
348
|
```
|
345
349
|
|
346
350
|
This should ease transferring data you need within the component mostly.
|
347
351
|
|
348
|
-
|
352
|
+
The same method is applicable for:
|
353
|
+
|
354
|
+
- The model itself
|
355
|
+
- It returns only the labels: Same result like above, but without the `values` key
|
356
|
+
- `ActiveRecord::Relation`
|
357
|
+
- Same result like above, but `values` then is a Array.
|
349
358
|
|
350
|
-
|
359
|
+
If a association returns a empty result, the labels are still calculated.
|
360
|
+
|
361
|
+
`offset` and `limit` are reserved keys, so, columns with the same name would be ignored.
|
362
|
+
|
363
|
+
**Caching:**
|
364
|
+
|
365
|
+
Caching Capability is not implemented on this method, you easily can wrap it by `Redis`
|
366
|
+
|
367
|
+
If used on the `cached_svelte_component` view helper,
|
368
|
+
the component's attributes are used to generate a checksum, which serves as the
|
369
|
+
cache key for efficient storage and retrieval. So, this method is meant to
|
370
|
+
make it easier to exactly filter out only the information that is needed
|
371
|
+
on the component.
|
351
372
|
|
352
373
|
## Caching
|
353
374
|
|
@@ -388,39 +409,19 @@ on the svelte-on-rails config file or pass the `expires_in` as argument to the v
|
|
388
409
|
|
389
410
|
Pass `debug: true` to the helper and you will see on the logs how your configuration works.
|
390
411
|
|
391
|
-
## ActionCable
|
412
|
+
## ActionCable vs. TurboStream
|
392
413
|
|
393
414
|
There are two ways that the server can talk to the client over Websocket:
|
394
415
|
|
395
|
-
- ActionCable transmits directly to the frontends javascript
|
396
|
-
- TurboStreams is a wrapper around ActionCable
|
397
|
-
- You always need a html part for communication
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
Check the regarding keys and their commends on the [config file](https://gitlab.com/sedl/svelte-on-rails/-/blob/main/templates/config_base/config/svelte_on_rails.yml?ref_type=heads).
|
402
|
-
From there, you just need:
|
403
|
-
|
404
|
-
```yaml
|
405
|
-
turbo_stream:
|
406
|
-
target_html_id: 'svelte-on-rails-stream-actions-box'
|
407
|
-
channel: 'public'
|
408
|
-
```
|
409
|
-
|
410
|
-
## ActionCable vs TurboStream
|
411
|
-
|
412
|
-
- **ActionCable**
|
413
|
-
- Cleaner setup no html needed
|
414
|
-
- Seams to initialize securer, especially for testings (not: production)
|
415
|
-
- **TurboStream**
|
416
|
-
- Secured Streams by html-tag `signed-stream-name` if you want to send confidential data
|
417
|
-
over streams or have different channels for each user privileges
|
418
|
-
- Has [Compatibility issue with UJS](https://github.com/hotwired/turbo-rails?tab=readme-ov-file#compatibility-with-rails-ujs)
|
416
|
+
- **ActionCable** transmits directly to the frontends javascript
|
417
|
+
- **TurboStreams** is a wrapper around ActionCable
|
418
|
+
- You always need a html part for communication by secured channels
|
419
|
+
- Makes sense when you want to transfer confidential data or separate onto privileged user channels
|
420
|
+
- Has [compatibility issues with Rails-UJS](https://github.com/hotwired/turbo-rails?tab=readme-ov-file#compatibility-with-rails-ujs)
|
419
421
|
|
422
|
+
|
420
423
|
## SvelteOnRails::ActionCable
|
421
424
|
|
422
|
-
ActionCable is the more basic library behind `TurboStream` and it is a second Option to call Javascript Actions from the server.
|
423
|
-
|
424
425
|
**Setup**
|
425
426
|
|
426
427
|
Add `app/channels/svelte_on_rails_channel.rb`
|
@@ -437,7 +438,14 @@ class SvelteOnRailsChannel < ApplicationCable::Channel
|
|
437
438
|
end
|
438
439
|
```
|
439
440
|
|
440
|
-
|
441
|
+
config
|
442
|
+
|
443
|
+
```yaml
|
444
|
+
action_cable:
|
445
|
+
channel: "svelte_on_rails_channel"
|
446
|
+
```
|
447
|
+
|
448
|
+
javascript
|
441
449
|
|
442
450
|
```shell
|
443
451
|
npm i @rails/actioncable
|
@@ -510,11 +518,6 @@ on the whole `document` and fires the given event there.
|
|
510
518
|
|
511
519
|
# SvelteOnRails::TurboStream
|
512
520
|
|
513
|
-
Turbo Stream makes more sense when you think of sending confidential data to the components
|
514
|
-
or you want to separate to channels based on user groups, for example.
|
515
|
-
|
516
|
-
Few setup is needed for that:
|
517
|
-
|
518
521
|
**Setup**
|
519
522
|
|
520
523
|
Please setup the `turbo-rails` gem and follow the chapter [Come alive with Turbo Streams](https://github.com/hotwired/turbo-rails?tab=readme-ov-file#come-alive-with-turbo-streams), which mainly is:
|
@@ -541,6 +544,17 @@ you can test it by:
|
|
541
544
|
|
542
545
|
When this works you are good to go.
|
543
546
|
|
547
|
+
**Configs**
|
548
|
+
|
549
|
+
Check the regarding keys and their commends on the [config file](https://gitlab.com/sedl/svelte-on-rails/-/blob/main/templates/config_base/config/svelte_on_rails.yml?ref_type=heads).
|
550
|
+
From there, you just need:
|
551
|
+
|
552
|
+
```yaml
|
553
|
+
turbo_stream:
|
554
|
+
target_html_id: 'svelte-on-rails-stream-actions-box'
|
555
|
+
channel: 'public'
|
556
|
+
```
|
557
|
+
|
544
558
|
**Minimal Usage Example**
|
545
559
|
|
546
560
|
And call this by:
|
data/lib/svelte-on-rails.rb
CHANGED
@@ -1,36 +1,40 @@
|
|
1
1
|
# lib/svelte_on_rails/active_record_extensions.rb
|
2
2
|
module SvelteOnRails
|
3
3
|
module ActiveRecordExtensions
|
4
|
-
def self.included(base)
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
end
|
4
|
+
# def self.included(base)
|
5
|
+
# unless defined?(ActiveRecord::Base) && base.ancestors.include?(ActiveRecord::Base)
|
6
|
+
# raise 'SvelteOnRails::ActiveRecordExtensions can only be included in ActiveRecord models'
|
7
|
+
# end
|
8
|
+
# end
|
9
9
|
|
10
10
|
# Returns a hash of attributes, methods, and associations formatted for Svelte components
|
11
|
-
def
|
12
|
-
@
|
11
|
+
def to_svelte(*attributes)
|
12
|
+
@to_svelte ||= begin
|
13
13
|
|
14
|
-
|
14
|
+
cl = SvelteOnRails::Lib::SvelteAttributes
|
15
|
+
cl.new.calculate_instance(self, attributes)
|
15
16
|
|
16
|
-
|
17
|
-
|
18
|
-
limit = opts[:limit]
|
19
|
-
attr = if offset || limit
|
20
|
-
unless self.respond_to?(:each)
|
21
|
-
raise 'offset and limit are only supported for record sets that respond to :each'
|
22
|
-
end
|
23
|
-
_opts = opts.reject { |key, _| [:offset, :limit].include?(key) }
|
24
|
-
attributes.select { |item| !item.is_a?(Hash) }.push(_opts)
|
25
|
-
else
|
26
|
-
attributes
|
27
|
-
end
|
17
|
+
end
|
18
|
+
end
|
28
19
|
|
29
|
-
|
30
|
-
utils.svelte_attributes(self, attr, offset: offset, limit: limit)
|
20
|
+
end
|
31
21
|
|
22
|
+
module ActiveRecordClassExtensions
|
23
|
+
def to_svelte(*attributes)
|
24
|
+
@to_svelte ||= begin
|
25
|
+
cl = SvelteOnRails::Lib::SvelteAttributes
|
26
|
+
cl.new.calculate_class(self, attributes)
|
32
27
|
end
|
33
28
|
end
|
29
|
+
end
|
34
30
|
|
31
|
+
module ActiveRecordRelationExtensions
|
32
|
+
def to_svelte(*attributes)
|
33
|
+
@to_svelte ||= begin
|
34
|
+
cl = SvelteOnRails::Lib::SvelteAttributes
|
35
|
+
cl.new.calculate_relation(self, attributes)
|
36
|
+
end
|
37
|
+
end
|
35
38
|
end
|
39
|
+
|
36
40
|
end
|
@@ -0,0 +1,190 @@
|
|
1
|
+
module SvelteOnRails
|
2
|
+
module Lib
|
3
|
+
class SvelteAttributes
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@labels = {}
|
7
|
+
end
|
8
|
+
|
9
|
+
def calculate_instance(record, attributes, call_stack: 0, offset: nil, limit: nil)
|
10
|
+
|
11
|
+
next_stack = call_stack + 1
|
12
|
+
|
13
|
+
if record.respond_to?(:each)
|
14
|
+
|
15
|
+
recs2 = if offset || limit
|
16
|
+
if (record.is_a?(ActiveRecord::Relation) || record.is_a?(ActiveRecord::Associations::CollectionProxy) rescue false)
|
17
|
+
_recs = (offset ? record.offset(offset) : record)
|
18
|
+
(limit ? _recs.limit(limit) : _recs)
|
19
|
+
elsif record.respond_to?(:drop) && record.respond_to?(:take) # that might be a array
|
20
|
+
_recs = offset ? record.drop(offset) : record
|
21
|
+
limit ? _recs.take(limit) : _recs
|
22
|
+
else
|
23
|
+
raise "[svelte-on-rails:to_svelte] unknown class for records: #{record}"
|
24
|
+
end
|
25
|
+
else
|
26
|
+
record
|
27
|
+
end
|
28
|
+
|
29
|
+
set_labels(record.first, attributes)
|
30
|
+
|
31
|
+
values = recs2.map do |rec|
|
32
|
+
calculate_instance(rec, attributes, call_stack: next_stack)
|
33
|
+
end
|
34
|
+
|
35
|
+
else
|
36
|
+
|
37
|
+
# we have a single record
|
38
|
+
|
39
|
+
values = {}
|
40
|
+
|
41
|
+
set_labels(record, attributes)
|
42
|
+
|
43
|
+
attributes.each do |attr|
|
44
|
+
|
45
|
+
if attr.is_a? Hash
|
46
|
+
|
47
|
+
# we have associations
|
48
|
+
attr.each do |key, value|
|
49
|
+
next if ['offset', 'limit'].include?(key.to_s)
|
50
|
+
_offset, _limit, _value = extract_limit(value)
|
51
|
+
|
52
|
+
_key = key.to_s
|
53
|
+
|
54
|
+
# inspect association and set_labels
|
55
|
+
|
56
|
+
reflect = record.class.reflect_on_association(_key)
|
57
|
+
raise "invalid association: #{_key}" unless reflect
|
58
|
+
set_labels(reflect, value)
|
59
|
+
|
60
|
+
# values
|
61
|
+
|
62
|
+
recs = record.send(_key)
|
63
|
+
if recs.present?
|
64
|
+
if recs.respond_to?(:each)
|
65
|
+
values[_key] = calculate_instance(
|
66
|
+
recs,
|
67
|
+
value,
|
68
|
+
call_stack: next_stack,
|
69
|
+
offset: _offset,
|
70
|
+
limit: _limit
|
71
|
+
)
|
72
|
+
else
|
73
|
+
values[_key] = calculate_instance(
|
74
|
+
recs,
|
75
|
+
value,
|
76
|
+
call_stack: next_stack
|
77
|
+
)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
else
|
83
|
+
# we have attributes
|
84
|
+
raise 'Invalid attribute' unless [Symbol, String].include?(attr.class)
|
85
|
+
_key = attr.to_s
|
86
|
+
|
87
|
+
values[_key] = record.send(_key)
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
if call_stack >= 1
|
94
|
+
values
|
95
|
+
else
|
96
|
+
{ 'values' => values }.merge(@labels)
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
|
101
|
+
def calculate_class(model, attributes, call_stack: 0)
|
102
|
+
|
103
|
+
next_stack = call_stack + 1
|
104
|
+
|
105
|
+
set_labels(model, attributes)
|
106
|
+
|
107
|
+
hash = attributes.find { |element| element.is_a?(Hash) } || {}
|
108
|
+
hash.each do |key, value|
|
109
|
+
reflect = model.reflect_on_association(key.to_s)
|
110
|
+
if reflect
|
111
|
+
calculate_class(
|
112
|
+
reflect,
|
113
|
+
value,
|
114
|
+
call_stack: next_stack
|
115
|
+
)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
if call_stack == 0
|
120
|
+
@labels
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def calculate_relation(relation, attributes, call_stack: 0)
|
125
|
+
set_labels(relation.klass, attributes)
|
126
|
+
values = relation.map do |rec|
|
127
|
+
calculate_instance(rec, attributes)['values']
|
128
|
+
end
|
129
|
+
{
|
130
|
+
'values' => values
|
131
|
+
}.merge(@labels)
|
132
|
+
end
|
133
|
+
|
134
|
+
private
|
135
|
+
|
136
|
+
def extract_limit(attributes)
|
137
|
+
|
138
|
+
_hash_args = attributes.grep(Hash).first.dup
|
139
|
+
attr, lim = if _hash_args.present?
|
140
|
+
hash_args = _hash_args.transform_keys { |key| key.to_s } # multiple arrays is not possible
|
141
|
+
hash_remainder = hash_args.reject { |key, _| %w[offset limit].include?(key.to_s) }
|
142
|
+
_attr = attributes.reject { |item| item.is_a?(Hash) }
|
143
|
+
[
|
144
|
+
if hash_remainder.any?
|
145
|
+
_attr + [hash_remainder]
|
146
|
+
else
|
147
|
+
_attr
|
148
|
+
end,
|
149
|
+
hash_args
|
150
|
+
]
|
151
|
+
else
|
152
|
+
[
|
153
|
+
attributes,
|
154
|
+
{}
|
155
|
+
]
|
156
|
+
end
|
157
|
+
|
158
|
+
[
|
159
|
+
lim['offset'],
|
160
|
+
lim['limit'],
|
161
|
+
attr
|
162
|
+
]
|
163
|
+
end
|
164
|
+
|
165
|
+
def set_labels(record, keys)
|
166
|
+
|
167
|
+
first_hash = keys.find { |element| element.is_a?(Hash) }
|
168
|
+
_keys = keys.reject { |element| element.is_a?(Hash) }
|
169
|
+
_keys += first_hash.keys if first_hash
|
170
|
+
|
171
|
+
_keys.each do |attr|
|
172
|
+
unless attr.respond_to?(:each)
|
173
|
+
obj = if record.respond_to?(:human_attribute_name)
|
174
|
+
record
|
175
|
+
elsif record.class.respond_to?(:human_attribute_name)
|
176
|
+
record.class
|
177
|
+
end
|
178
|
+
|
179
|
+
next unless obj
|
180
|
+
|
181
|
+
@labels["#{obj.to_s.underscore}_labels"] ||= {}
|
182
|
+
@labels["#{obj.to_s.underscore}_labels"][attr.to_s] ||= obj.human_attribute_name(attr)
|
183
|
+
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
@@ -163,132 +163,6 @@ module SvelteOnRails
|
|
163
163
|
end
|
164
164
|
end
|
165
165
|
|
166
|
-
def self.svelte_attributes(record, attributes, labels: {}, call_stack: 0, offset: nil, limit: nil)
|
167
|
-
|
168
|
-
if record.is_a?(Class)
|
169
|
-
|
170
|
-
# this is the case if a belongs_to association is empty; In that case we pass the class itself and extract only the labels
|
171
|
-
raise 'limit and offset are supported only for iterable objects' if limit || offset
|
172
|
-
attributes.each do |attr|
|
173
|
-
unless attr.respond_to?(:each)
|
174
|
-
labels["#{record.to_s.underscore}_labels"] ||= {}
|
175
|
-
labels["#{record.to_s.underscore}_labels"][attr.to_s] ||= record.human_attribute_name(attr)
|
176
|
-
end
|
177
|
-
end
|
178
|
-
values = {}
|
179
|
-
|
180
|
-
elsif record.respond_to?(:each)
|
181
|
-
|
182
|
-
unless record.is_a?(ActiveRecord::Relation) || record.is_a?(ActiveRecord::Associations::CollectionProxy)
|
183
|
-
raise 'record set must be a Article::ActiveRecord_Associations_CollectionProxy'
|
184
|
-
end
|
185
|
-
|
186
|
-
recs = (offset ? record.offset(offset) : record)
|
187
|
-
recs2 = (limit ? recs.limit(limit) : recs)
|
188
|
-
|
189
|
-
values = recs2.map do |rec|
|
190
|
-
svelte_attributes(rec, attributes, labels: labels, call_stack: call_stack + 1)
|
191
|
-
end
|
192
|
-
|
193
|
-
else
|
194
|
-
|
195
|
-
# we have a single record
|
196
|
-
|
197
|
-
raise 'limit and offset are supported only for iterable objects' if limit || offset
|
198
|
-
values = {}
|
199
|
-
|
200
|
-
table_name = record.class.to_s.underscore
|
201
|
-
|
202
|
-
attributes.each do |attr|
|
203
|
-
|
204
|
-
if attr.is_a? Hash
|
205
|
-
|
206
|
-
# we have associations
|
207
|
-
attr.each do |key, value|
|
208
|
-
_key = key.to_s
|
209
|
-
|
210
|
-
# skip and fetch offset and limit
|
211
|
-
if key.to_s.match(/_limit$/) && !record.respond_to?(key)
|
212
|
-
raise 'Invalid attribute' unless record.respond_to?(key.to_s[0..-7])
|
213
|
-
next
|
214
|
-
end
|
215
|
-
if key.to_s.match(/_offset$/) && !record.respond_to?(key)
|
216
|
-
raise 'Invalid attribute' unless record.respond_to?(key.to_s[0..-8])
|
217
|
-
next
|
218
|
-
end
|
219
|
-
offs, lim = svelte_attribute_extract_limit(record, attributes, _key)
|
220
|
-
|
221
|
-
labels["#{table_name}_labels"] ||= {}
|
222
|
-
labels["#{table_name}_labels"][_key] ||= record.class.human_attribute_name(_key)
|
223
|
-
|
224
|
-
# values
|
225
|
-
|
226
|
-
reflect = record.class.reflect_on_association(_key)
|
227
|
-
if reflect
|
228
|
-
recs = record.send(_key)
|
229
|
-
content = (recs.present? ? recs : reflect.active_record) # if no record, we extract only the labels
|
230
|
-
if content.respond_to?(:each)
|
231
|
-
values[_key] = svelte_attributes(
|
232
|
-
content,
|
233
|
-
value,
|
234
|
-
labels: labels,
|
235
|
-
call_stack: call_stack + 1,
|
236
|
-
offset: offs,
|
237
|
-
limit: lim
|
238
|
-
)
|
239
|
-
else
|
240
|
-
values[_key] = svelte_attributes(
|
241
|
-
content,
|
242
|
-
value,
|
243
|
-
labels: labels,
|
244
|
-
call_stack: call_stack + 1,
|
245
|
-
offset: offs,
|
246
|
-
limit: lim
|
247
|
-
)
|
248
|
-
end
|
249
|
-
else
|
250
|
-
raise "invalid association: #{_key}"
|
251
|
-
end
|
252
|
-
end
|
253
|
-
|
254
|
-
else
|
255
|
-
# we have attributes
|
256
|
-
raise 'Invalid attribute' unless [Symbol, String].include?(attr.class)
|
257
|
-
_key = attr.to_s
|
258
|
-
|
259
|
-
labels["#{table_name}_labels"] ||= {}
|
260
|
-
labels["#{table_name}_labels"][_key] ||= record.class.human_attribute_name(_key)
|
261
|
-
|
262
|
-
values[_key] = record.send(_key)
|
263
|
-
end
|
264
|
-
|
265
|
-
end
|
266
|
-
end
|
267
|
-
|
268
|
-
if call_stack >= 1
|
269
|
-
values
|
270
|
-
else
|
271
|
-
{ 'values' => values }.merge(labels)
|
272
|
-
end
|
273
|
-
|
274
|
-
end
|
275
|
-
|
276
|
-
private
|
277
|
-
|
278
|
-
def self.svelte_attribute_extract_limit(record, attributes, key)
|
279
|
-
|
280
|
-
hash_args = attributes.grep(Hash).first.with_indifferent_access # multiple arrays is not possible
|
281
|
-
|
282
|
-
offset = if hash_args["#{key}_offset"] && !record.respond_to?("#{key}_offset")
|
283
|
-
hash_args["#{key}_offset"]
|
284
|
-
end
|
285
|
-
|
286
|
-
limit = if hash_args["#{key}_limit"] && !record.respond_to?("#{key}_limit")
|
287
|
-
hash_args["#{key}_limit"]
|
288
|
-
end
|
289
|
-
|
290
|
-
[offset, limit]
|
291
|
-
end
|
292
166
|
end
|
293
167
|
end
|
294
168
|
end
|
@@ -79,7 +79,13 @@ module SvelteOnRails
|
|
79
79
|
|
80
80
|
def render_ssr
|
81
81
|
renderer = SvelteOnRails::Renderer.new(filename)
|
82
|
-
renderer.render(@svelte_props)
|
82
|
+
res = renderer.render(@svelte_props)
|
83
|
+
if res['html'].is_a?(Array)
|
84
|
+
res['html'] = res['html'].join
|
85
|
+
res
|
86
|
+
else
|
87
|
+
res
|
88
|
+
end
|
83
89
|
end
|
84
90
|
|
85
91
|
def custom_cache_key
|
@@ -15,10 +15,18 @@ module SvelteOnRails
|
|
15
15
|
|
16
16
|
initializer 'svelte_on_rails.active_record_extensions' do
|
17
17
|
ActiveSupport.on_load(:active_record) do
|
18
|
+
# Include instance-level extensions
|
18
19
|
include SvelteOnRails::ActiveRecordExtensions
|
20
|
+
# Extend with class-level extensions
|
21
|
+
extend SvelteOnRails::ActiveRecordClassExtensions
|
19
22
|
end
|
20
23
|
end
|
21
24
|
|
25
|
+
# Extend ActiveRecord::Relation
|
26
|
+
ActiveSupport.on_load(:active_record_relation) do
|
27
|
+
include SvelteOnRails::ActiveRecordRelationExtensions
|
28
|
+
end
|
29
|
+
|
22
30
|
rake_tasks do
|
23
31
|
load File.expand_path("../../tasks/svelte_on_rails_tasks.rake", __FILE__)
|
24
32
|
end
|
@@ -14,13 +14,13 @@ import {loadComponentModule, readPropsFromStdin} from './utils.js';
|
|
14
14
|
|
15
15
|
try {
|
16
16
|
MyComponent(payload, props); // Writes directly to payload.out
|
17
|
-
console.log(`[svelte-on-rails:debug] written to payload`)
|
17
|
+
console.log(`[svelte-on-rails:debug] written to payload (typeof payload.out => «${typeof payload.out}»)`)
|
18
18
|
} catch (error) {
|
19
19
|
console.error('[svelte-on-rails:debug] Error rendering component:', error);
|
20
20
|
process.exit(1);
|
21
21
|
}
|
22
22
|
|
23
|
-
const res = {status: 'SUCCESS', html: payload.out
|
23
|
+
const res = {status: 'SUCCESS', html: payload.out};
|
24
24
|
console.log('[svelte-on-rails:successful-json-response]' + JSON.stringify(res));
|
25
25
|
})();
|
26
26
|
|
@@ -5,10 +5,6 @@ class SvelteOnRailsHelloWorldController < ApplicationController
|
|
5
5
|
|
6
6
|
def web_socket_action
|
7
7
|
|
8
|
-
# render plain: Article.first.svelte_attributes(:name) #(:name, :calc_method, children: [:name], children_limit: 2, parent: [:name]).to_json
|
9
|
-
#
|
10
|
-
# return
|
11
|
-
|
12
8
|
comp = 'ReceiveFromChannel'
|
13
9
|
|
14
10
|
case params['stream']
|
@@ -1,5 +1,6 @@
|
|
1
1
|
import { createConsumer } from "@rails/actioncable"
|
2
|
-
import {dispatchSvelteStreamEvent, actionCableDebugLog} from '@csedl/svelte-on-rails'
|
2
|
+
import { SvelteOnRails, dispatchSvelteStreamEvent, actionCableDebugLog } from '@csedl/svelte-on-rails'
|
3
|
+
SvelteOnRails.debug = true
|
3
4
|
|
4
5
|
const consumer = createConsumer()
|
5
6
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: svelte-on-rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 6.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Christian Sedlmair
|
@@ -43,6 +43,7 @@ files:
|
|
43
43
|
- lib/svelte_on_rails/installer/utils.rb
|
44
44
|
- lib/svelte_on_rails/installer/vite.rb
|
45
45
|
- lib/svelte_on_rails/lib/development_utils.rb
|
46
|
+
- lib/svelte_on_rails/lib/to_svelte.rb
|
46
47
|
- lib/svelte_on_rails/lib/utils.rb
|
47
48
|
- lib/svelte_on_rails/lib/view_helper_support.rb
|
48
49
|
- lib/svelte_on_rails/railtie.rb
|