server_component 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +4 -2
- data/Gemfile +2 -0
- data/README.md +139 -20
- data/app/controllers/server_component/component_routers_controller.rb +2 -10
- data/figure.png +0 -0
- data/lib/generators/server_component/controller_generator.rb +15 -0
- data/lib/generators/server_component/install_generator.rb +0 -12
- data/lib/generators/templates/AFTER_INSTALL +7 -11
- data/lib/generators/templates/component_controller.rb.tt +1 -1
- data/lib/generators/templates/server_component.rb +1 -1
- data/lib/server_component.rb +5 -0
- data/lib/server_component/base.rb +7 -0
- data/{app/controllers/server_component/base_component_controller.rb → lib/server_component/component.rb} +14 -10
- data/lib/server_component/component_router.rb +8 -29
- data/lib/server_component/engine.rb +2 -1
- data/lib/server_component/engine/routes.rb +34 -0
- data/lib/server_component/version.rb +1 -1
- data/server_component.gemspec +2 -2
- metadata +9 -10
- data/app/controllers/server_component/components_controller.rb +0 -35
- data/config/routes.rb +0 -6
- data/lib/generators/server_component/component_controller_generator.rb +0 -28
- data/lib/generators/templates/api_component_router.rb +0 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4e2df6ac9d580c8c3caa04ef86a853ca4ecc5c4c1a527c5ab2a31e27e3f38e4d
|
4
|
+
data.tar.gz: ea199011564cddee7a37c342d1e4fcddb3d11b23021de8cf629ea4a0d1916b1e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 37e464b972ed2782ea3c0995711780de2ed383696a5bbf82feca5e9404de3cfbf23d507bfea11aba909b02feb9c8085164089e9966324684e45c78e9e3a236d9
|
7
|
+
data.tar.gz: 61a058355d9254f10d46d18b82b3979d38fdc99046f2665f45e7b6e24ef29b99d684eed47f7f0d6e919a7f8c0b036821d0cf3be415cc593f69547682e0cedcb1
|
data/.rubocop.yml
CHANGED
data/Gemfile
CHANGED
@@ -9,6 +9,7 @@ gem 'execjs'
|
|
9
9
|
gem 'stitch-rb'
|
10
10
|
|
11
11
|
group :development, :test do
|
12
|
+
gem 'ammeter'
|
12
13
|
gem 'capybara', '~> 2.18.0'
|
13
14
|
gem 'pry-byebug'
|
14
15
|
gem 'rspec-rails', '~> 3.8'
|
@@ -16,4 +17,5 @@ group :development, :test do
|
|
16
17
|
gem 'selenium-webdriver'
|
17
18
|
gem 'simplecov'
|
18
19
|
gem 'webpacker', '4.0.0.rc.2'
|
20
|
+
gem 'yard'
|
19
21
|
end
|
data/README.md
CHANGED
@@ -1,11 +1,21 @@
|
|
1
1
|
[![CircleCI](https://circleci.com/gh/effective-spa/server_component_rails.svg?style=svg)](https://circleci.com/gh/effective-spa/server_component_rails) [![codecov](https://codecov.io/gh/effective-spa/server_component_rails/branch/master/graph/badge.svg)](https://codecov.io/gh/effective-spa/server_component_rails) [![Maintainability](https://api.codeclimate.com/v1/badges/3a8af74f091ff7c3dbf4/maintainability)](https://codeclimate.com/github/effective-spa/server_component_rails/maintainability) [![Gem Version](https://badge.fury.io/rb/server_component.svg)](https://badge.fury.io/rb/server_component)
|
2
2
|
|
3
|
+
|
3
4
|
# ServerComponent
|
4
5
|
|
5
|
-
ServerComponent
|
6
|
-
|
6
|
+
**ServerComponent** is a painless framework for React apps.
|
7
|
+
|
8
|
+
*This gem is designed to be used with **npm package version of [server_component](https://github.com/effective-spa/server_component)**.*
|
9
|
+
|
10
|
+
### Why?
|
11
|
+
|
12
|
+
SPAs do not always require much-highly scalable technology stack. There need alternatives for those who want to keep less code with retaining expressiveness of SPA. ServerComponent is a smart one of them.
|
7
13
|
|
8
|
-
|
14
|
+
The following image depicts how it reduces the complexity among modules. You can get more development efficiency with keeping advantages of SPA as you choose ServerComponent.
|
15
|
+
|
16
|
+
![figure](https://github.com/effective-spa/server_component_rails/raw/master/figure.png)
|
17
|
+
|
18
|
+
### Installation
|
9
19
|
|
10
20
|
Add this line to your application's Gemfile and run `bundle install`:
|
11
21
|
|
@@ -19,18 +29,12 @@ Run this command to initialize configuration file and base classes.
|
|
19
29
|
$ rails generate server_component:install
|
20
30
|
```
|
21
31
|
|
22
|
-
|
23
|
-
|
24
|
-
```rb
|
25
|
-
config.autoload_paths << Rails.root.join('component_routers')
|
26
|
-
```
|
27
|
-
|
28
|
-
## Getting Started
|
32
|
+
## 🚀 Getting Started
|
29
33
|
|
30
34
|
Add a new component controller:
|
31
35
|
|
32
36
|
```rb
|
33
|
-
class CounterComponentController < ServerComponent::
|
37
|
+
class Api::CounterComponentController < ServerComponent::Base
|
34
38
|
def self.initial_state
|
35
39
|
{
|
36
40
|
count: 0
|
@@ -53,11 +57,11 @@ class CounterComponentController < ServerComponent::ComponentController
|
|
53
57
|
end
|
54
58
|
```
|
55
59
|
|
56
|
-
|
60
|
+
Add new lines into routes.rb:
|
57
61
|
|
58
62
|
```rb
|
59
|
-
|
60
|
-
component :counter
|
63
|
+
component_scope :api do
|
64
|
+
component :counter, actions: [:increment, :decrement]
|
61
65
|
end
|
62
66
|
```
|
63
67
|
|
@@ -92,7 +96,7 @@ class CounterBody extends Component {
|
|
92
96
|
class Main extends Component {
|
93
97
|
render() {
|
94
98
|
return (
|
95
|
-
<ServerComponent.Use
|
99
|
+
<ServerComponent.Use name="api">
|
96
100
|
<CounterContainer>
|
97
101
|
<CounterBody />
|
98
102
|
</CounterContainer>
|
@@ -104,6 +108,8 @@ class Main extends Component {
|
|
104
108
|
ReactDOM.render(<Main />, document.getElementById('root'));
|
105
109
|
```
|
106
110
|
|
111
|
+
(Note that the conventional Rails' meta tags for CSRF token are needed.)
|
112
|
+
|
107
113
|
If you don't use decorators, here's an alternative:
|
108
114
|
|
109
115
|
```js
|
@@ -116,15 +122,128 @@ const CounterBody = consume(class extends Component {
|
|
116
122
|
}, 'counter');
|
117
123
|
```
|
118
124
|
|
119
|
-
## API Documentation
|
120
125
|
|
121
|
-
|
126
|
+
## 🎓 Usage
|
127
|
+
|
128
|
+
### Write view files with [Jsrb](https://github.com/effective-spa/jsrb)
|
122
129
|
|
123
|
-
|
130
|
+
[Jsrb](https://github.com/effective-spa/jsrb), a view handler that generates JavaScript, is included in this library. Because the action of the server component merely renders executable JavaScript code instead of JSON, you have to build code safely. But don't be serious! Most of state updating functions won't be much complicated. Using `Jsrb`, you can easily and safely construct JavaScript code.
|
131
|
+
|
132
|
+
#### Example
|
133
|
+
|
134
|
+
In `controllers/books_component_controller.rb`:
|
135
|
+
|
136
|
+
```rb
|
137
|
+
action :create
|
138
|
+
def create
|
139
|
+
@book = Book.new(book_params)
|
140
|
+
@book.save
|
141
|
+
render :js
|
142
|
+
end
|
143
|
+
```
|
144
|
+
|
145
|
+
In `views/books_component/create.js.jsrb`:
|
146
|
+
|
147
|
+
```rb
|
148
|
+
# Note that set_state must take `js` as an argument.
|
149
|
+
set_state(js) do |s|
|
150
|
+
s.total { |prev| prev + 1 }
|
151
|
+
s.books do |books|
|
152
|
+
books.concat id: @book.id, title: @book.title
|
153
|
+
end
|
154
|
+
end
|
155
|
+
```
|
156
|
+
|
157
|
+
### Fallback to conventional JSON handling
|
158
|
+
|
159
|
+
The component controller is just a Rails controller, so you can render JSON in a conventional manner. The client side handles response by Content-Type and status properly, so you don't have to reconstruct the status handling logic.
|
160
|
+
|
161
|
+
#### Example
|
162
|
+
|
163
|
+
In `controllers/books_component_controller.rb`:
|
164
|
+
|
165
|
+
```rb
|
166
|
+
action :create
|
167
|
+
def create
|
168
|
+
@book = Book.new(book_params)
|
169
|
+
if @book.save
|
170
|
+
render json: { book: { id: @book.id, title: @book.title }
|
171
|
+
else
|
172
|
+
render json: { errors: @book.error_messages }, status: :unprocessable_entity
|
173
|
+
end
|
174
|
+
end
|
175
|
+
```
|
176
|
+
|
177
|
+
In frontend:
|
178
|
+
|
179
|
+
```js
|
180
|
+
@server_component('book')
|
181
|
+
class BookContainer extends Component {
|
182
|
+
// method name sufixed with `Ok` automatically
|
183
|
+
// executed after 2XX response
|
184
|
+
createOk({ book }) {
|
185
|
+
this.setState({
|
186
|
+
books: this.state.books.concat(book),
|
187
|
+
});
|
188
|
+
}
|
189
|
+
|
190
|
+
// method name sufixed with `Err` automatically
|
191
|
+
// executed after 4XX response
|
192
|
+
createErr({ errors }) {
|
193
|
+
this.setState({ errors });
|
194
|
+
}
|
195
|
+
}
|
196
|
+
```
|
197
|
+
|
198
|
+
### Utility for temporary UI state
|
199
|
+
|
200
|
+
It is a common UI pattern to display the user operated resource in a particular state while waiting the server response. In such cases, you have to `setState` in a certain component before request. ServerComponent's controller has an utility to implement this behavior.
|
201
|
+
|
202
|
+
#### Example
|
203
|
+
|
204
|
+
```rb
|
205
|
+
action :create do |c|
|
206
|
+
c.before do |s, data|
|
207
|
+
# data is a request payload
|
208
|
+
s.books do |book|
|
209
|
+
book.concat title: data[:title], creating: true
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
213
|
+
def create
|
214
|
+
@book = Book.new(book_params)
|
215
|
+
@book.save
|
216
|
+
set_state do |s|
|
217
|
+
s.books do |books|
|
218
|
+
books = books.filter { |b| !b[:creating] }
|
219
|
+
if @book.persisted?
|
220
|
+
books.push id: @book.id, title: @book.title
|
221
|
+
end
|
222
|
+
books
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
226
|
+
```
|
227
|
+
|
228
|
+
### Uploading files
|
229
|
+
|
230
|
+
File uploading requires FormData request because its Content-Type must be `multipart/form-data`. You have to specify explicitly that the action should accept file if you need.
|
231
|
+
|
232
|
+
#### Example
|
233
|
+
|
234
|
+
```rb
|
235
|
+
action :upload do |c|
|
236
|
+
c.accept_file!
|
237
|
+
end
|
238
|
+
def upload
|
239
|
+
params[:file] # => ActionDispatch::Http::UploadedFile
|
240
|
+
end
|
241
|
+
```
|
124
242
|
|
125
|
-
|
243
|
+
## 🤝 Contributing
|
126
244
|
|
245
|
+
**Contributions are extremely welcome on Github Issue or Pull Request!**
|
127
246
|
|
128
|
-
## License
|
247
|
+
## 📝 License
|
129
248
|
|
130
249
|
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
@@ -3,21 +3,13 @@
|
|
3
3
|
module ServerComponent
|
4
4
|
class ComponentRoutersController < ServerComponent.parent_controller.constantize
|
5
5
|
def show
|
6
|
-
component_router = find_component_router
|
7
6
|
render json: component_router.to_json
|
8
7
|
end
|
9
8
|
|
10
9
|
private
|
11
10
|
|
12
|
-
def
|
13
|
-
|
14
|
-
component_router_class =
|
15
|
-
begin
|
16
|
-
component_router_class_name.constantize
|
17
|
-
rescue NameError
|
18
|
-
raise ActionController::RoutingError, "No route matches routes/#{name}"
|
19
|
-
end
|
20
|
-
component_router_class.new
|
11
|
+
def component_router
|
12
|
+
ServerComponent.mappings[name] || raise
|
21
13
|
end
|
22
14
|
|
23
15
|
def name
|
data/figure.png
ADDED
Binary file
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ServerComponent
|
4
|
+
module Generators
|
5
|
+
class ControllerGenerator < Rails::Generators::NamedBase
|
6
|
+
source_root File.expand_path('../templates', __dir__)
|
7
|
+
|
8
|
+
desc 'Creates a ServerComponent initializer.'
|
9
|
+
|
10
|
+
def create_controller_file
|
11
|
+
template 'component_controller.rb', File.join('app/controllers', class_path, "#{file_name}_component_controller.rb")
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -11,18 +11,6 @@ module ServerComponent
|
|
11
11
|
template 'server_component.rb', 'config/initializers/server_component.rb'
|
12
12
|
end
|
13
13
|
|
14
|
-
def setup_route
|
15
|
-
route "mount ServerComponent::Engine, at: 'react'"
|
16
|
-
end
|
17
|
-
|
18
|
-
def create_directory
|
19
|
-
empty_directory 'app/component_routers'
|
20
|
-
end
|
21
|
-
|
22
|
-
def add_one_router
|
23
|
-
template 'api_component_router.rb', 'app/component_routers/api_component_router.rb'
|
24
|
-
end
|
25
|
-
|
26
14
|
def show_readme
|
27
15
|
readme 'AFTER_INSTALL' if behavior == :invoke
|
28
16
|
end
|
@@ -2,27 +2,23 @@
|
|
2
2
|
|
3
3
|
What's next:
|
4
4
|
|
5
|
-
1.
|
6
|
-
in config/application.rb
|
5
|
+
1. Create component controller. If you want BookComponent for example, run:
|
7
6
|
|
8
|
-
|
7
|
+
$ rails generate server_component:controller book
|
9
8
|
|
10
9
|
|
11
|
-
2.
|
10
|
+
2. Instantiate component class in the client with `server_component` package:
|
12
11
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
3. Conjoin client application with `server_component`:
|
12
|
+
import ServerComponent, { server_component, consumer } from 'server_component';
|
17
13
|
|
18
14
|
// Create a component class.
|
19
15
|
|
20
|
-
@
|
16
|
+
@server_component('book')
|
21
17
|
class BookContainer extends React.Component {}
|
22
18
|
|
23
19
|
// Create a component-attached class.
|
24
20
|
|
25
|
-
@
|
21
|
+
@consumer('book')
|
26
22
|
class Book extends React.Component {
|
27
23
|
render() {
|
28
24
|
const { state: { list } } = this.props.book;
|
@@ -36,7 +32,7 @@ What's next:
|
|
36
32
|
|
37
33
|
// And use in your root render function:
|
38
34
|
|
39
|
-
<ServerComponent.Use
|
35
|
+
<ServerComponent.Use name="api">
|
40
36
|
<BookContainer>
|
41
37
|
<Book />
|
42
38
|
</BookContainer>
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
# Use this hook to configure ServerComponent
|
4
4
|
ServerComponent.setup do |config|
|
5
|
-
# context_script is
|
5
|
+
# context_script is prepended to response scripts.
|
6
6
|
# It is useful if you want to add functions
|
7
7
|
# invoked from JSRB renderer.
|
8
8
|
# You can get identifiers from JSRB by calling
|
data/lib/server_component.rb
CHANGED
@@ -5,7 +5,9 @@ require 'jsrb'
|
|
5
5
|
|
6
6
|
module ServerComponent
|
7
7
|
autoload :VERSION, 'server_component/version'
|
8
|
+
autoload :Base, 'server_component/base'
|
8
9
|
autoload :ComponentRouter, 'server_component/component_router'
|
10
|
+
autoload :Component, 'server_component/component'
|
9
11
|
|
10
12
|
class NamespaceNotFound < StandardError; end
|
11
13
|
|
@@ -16,6 +18,9 @@ module ServerComponent
|
|
16
18
|
yield self
|
17
19
|
end
|
18
20
|
|
21
|
+
mattr_accessor :mappings
|
22
|
+
@@mappings = {}
|
23
|
+
|
19
24
|
mattr_accessor :context_script
|
20
25
|
@@context_script = ''
|
21
26
|
|
@@ -28,21 +28,25 @@ module ServerComponent
|
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
31
|
-
|
32
|
-
|
31
|
+
module Component
|
32
|
+
extend ActiveSupport::Concern
|
33
33
|
|
34
|
-
|
35
|
-
|
34
|
+
included do
|
35
|
+
class_attribute :initial_state, :action_on_mount
|
36
36
|
|
37
|
-
|
37
|
+
helper ServerComponentHelper
|
38
|
+
include ServerComponentHelper
|
38
39
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
40
|
+
private
|
41
|
+
|
42
|
+
def set_state(&block) # rubocop:disable Naming/AccessorMethodName
|
43
|
+
jsrb = Jsrb::Base.new
|
44
|
+
super(jsrb, &block)
|
45
|
+
render jsrb: jsrb.generate_code
|
46
|
+
end
|
43
47
|
end
|
44
48
|
|
45
|
-
|
49
|
+
class_methods do
|
46
50
|
def to_json
|
47
51
|
{
|
48
52
|
action_on_mount: action_on_mount,
|
@@ -2,7 +2,12 @@
|
|
2
2
|
|
3
3
|
module ServerComponent
|
4
4
|
class ComponentRouter
|
5
|
-
|
5
|
+
attr_reader :namespace, :components
|
6
|
+
|
7
|
+
def initialize(namespace = nil)
|
8
|
+
@namespace = namespace
|
9
|
+
@components = []
|
10
|
+
end
|
6
11
|
|
7
12
|
def to_json
|
8
13
|
h = {}
|
@@ -14,12 +19,8 @@ module ServerComponent
|
|
14
19
|
h
|
15
20
|
end
|
16
21
|
|
17
|
-
def
|
18
|
-
|
19
|
-
end
|
20
|
-
|
21
|
-
def namespace
|
22
|
-
self.class._namespace
|
22
|
+
def add_component(name)
|
23
|
+
@components << name.to_sym
|
23
24
|
end
|
24
25
|
|
25
26
|
def context_script
|
@@ -32,27 +33,5 @@ module ServerComponent
|
|
32
33
|
name = (namespace ? "#{namespace}/#{component}" : component).to_s
|
33
34
|
"#{name.camelize}ComponentController".constantize
|
34
35
|
end
|
35
|
-
|
36
|
-
class << self
|
37
|
-
def namespace(mod)
|
38
|
-
self._namespace = mod
|
39
|
-
end
|
40
|
-
|
41
|
-
def components
|
42
|
-
if instance_variable_defined?('@components')
|
43
|
-
instance_variable_get '@components'
|
44
|
-
else
|
45
|
-
a = []
|
46
|
-
instance_variable_set '@components', a
|
47
|
-
a
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
def component(*component_names)
|
52
|
-
component_names.each do |name|
|
53
|
-
components << name.to_sym
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
57
36
|
end
|
58
37
|
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActionDispatch
|
4
|
+
module Routing
|
5
|
+
class Mapper
|
6
|
+
# component_scope :api do
|
7
|
+
# component :counter, actions: [:hoge]
|
8
|
+
# end
|
9
|
+
#
|
10
|
+
# will generate
|
11
|
+
#
|
12
|
+
# /api => Description Endpoint
|
13
|
+
# /api/counter/hoge => Component Endpoints
|
14
|
+
def component_scope(*args)
|
15
|
+
path = args.first.to_s
|
16
|
+
get "/#{path}", controller: 'server_component/component_routers', action: 'show', name: path
|
17
|
+
namespace(*args) do
|
18
|
+
@current_component_router = ServerComponent::ComponentRouter.new(@scope[:module])
|
19
|
+
yield
|
20
|
+
end
|
21
|
+
ServerComponent.mappings[path] = @current_component_router
|
22
|
+
@current_component_router = nil
|
23
|
+
end
|
24
|
+
|
25
|
+
def component(name, options = {})
|
26
|
+
actions = [options.fetch(:actions, [])].flatten(1)
|
27
|
+
actions.each do |action|
|
28
|
+
post "/#{name}/#{action}", controller: "#{name}_component", action: action
|
29
|
+
end
|
30
|
+
@current_component_router.add_component(name)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/server_component.gemspec
CHANGED
@@ -10,8 +10,8 @@ Gem::Specification.new do |spec|
|
|
10
10
|
spec.authors = ['Shun MIZUKAMI']
|
11
11
|
spec.email = ['norainu234@gmail.com']
|
12
12
|
|
13
|
-
spec.summary = '
|
14
|
-
spec.description = '
|
13
|
+
spec.summary = 'A painless framework for React apps.'
|
14
|
+
spec.description = 'A painless framework for React apps.'
|
15
15
|
spec.homepage = 'https://github.com/effective-spa/server_component_rails'
|
16
16
|
spec.license = 'MIT'
|
17
17
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: server_component
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shun MIZUKAMI
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-02-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: jsrb
|
@@ -86,8 +86,7 @@ dependencies:
|
|
86
86
|
- - "~>"
|
87
87
|
- !ruby/object:Gem::Version
|
88
88
|
version: '3.0'
|
89
|
-
description:
|
90
|
-
controller
|
89
|
+
description: A painless framework for React apps.
|
91
90
|
email:
|
92
91
|
- norainu234@gmail.com
|
93
92
|
executables: []
|
@@ -103,22 +102,22 @@ files:
|
|
103
102
|
- Gemfile
|
104
103
|
- README.md
|
105
104
|
- Rakefile
|
106
|
-
- app/controllers/server_component/base_component_controller.rb
|
107
105
|
- app/controllers/server_component/component_routers_controller.rb
|
108
|
-
- app/controllers/server_component/components_controller.rb
|
109
106
|
- app/helpers/server_component_helper.rb
|
110
107
|
- bin/rails
|
111
108
|
- bin/webpack
|
112
|
-
-
|
113
|
-
- lib/generators/server_component/
|
109
|
+
- figure.png
|
110
|
+
- lib/generators/server_component/controller_generator.rb
|
114
111
|
- lib/generators/server_component/install_generator.rb
|
115
112
|
- lib/generators/templates/AFTER_INSTALL
|
116
|
-
- lib/generators/templates/api_component_router.rb
|
117
113
|
- lib/generators/templates/component_controller.rb.tt
|
118
114
|
- lib/generators/templates/server_component.rb
|
119
115
|
- lib/server_component.rb
|
116
|
+
- lib/server_component/base.rb
|
117
|
+
- lib/server_component/component.rb
|
120
118
|
- lib/server_component/component_router.rb
|
121
119
|
- lib/server_component/engine.rb
|
120
|
+
- lib/server_component/engine/routes.rb
|
122
121
|
- lib/server_component/js_function_builder.rb
|
123
122
|
- lib/server_component/version.rb
|
124
123
|
- server_component.gemspec
|
@@ -146,5 +145,5 @@ rubyforge_project:
|
|
146
145
|
rubygems_version: 2.7.6
|
147
146
|
signing_key:
|
148
147
|
specification_version: 4
|
149
|
-
summary:
|
148
|
+
summary: A painless framework for React apps.
|
150
149
|
test_files: []
|
@@ -1,35 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module ServerComponent
|
4
|
-
class ComponentsController < ServerComponent.parent_controller.constantize
|
5
|
-
def perform
|
6
|
-
component_class = find_component_class!
|
7
|
-
component_class.dispatch(component_action, request, response)
|
8
|
-
end
|
9
|
-
|
10
|
-
private
|
11
|
-
|
12
|
-
def find_component_class!
|
13
|
-
klass_name = "#{component_name.camelize}ComponentController"
|
14
|
-
klass =
|
15
|
-
begin
|
16
|
-
klass_name.constantize
|
17
|
-
rescue NameError
|
18
|
-
raise ActionController::RoutingError, "No route matches #{component_name}/#{component_action}"
|
19
|
-
end
|
20
|
-
unless klass <= ServerComponent::BaseComponentController
|
21
|
-
raise ActionController::RoutingError, "No route matches #{component_name}/#{component_action}"
|
22
|
-
end
|
23
|
-
|
24
|
-
klass
|
25
|
-
end
|
26
|
-
|
27
|
-
def component_name
|
28
|
-
params[:component_name]
|
29
|
-
end
|
30
|
-
|
31
|
-
def component_action
|
32
|
-
params[:component_action_name]
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
data/config/routes.rb
DELETED
@@ -1,28 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module ServerComponent
|
4
|
-
module Generators
|
5
|
-
class ComponentControllerGenerator < Rails::Generators::NamedBase
|
6
|
-
source_root File.expand_path('../templates', __dir__)
|
7
|
-
|
8
|
-
desc 'Creates a ServerComponent initializer.'
|
9
|
-
|
10
|
-
def create_controller_file
|
11
|
-
template 'component_controller.rb', File.join('app/controllers', class_path, "#{file_name}_component_controller.rb")
|
12
|
-
end
|
13
|
-
|
14
|
-
def component
|
15
|
-
rgx = /class [A-z::]+ComponentRouter < ServerComponent::ComponentRouter\n/
|
16
|
-
router_path = File.join('app/component_routers', "#{router_name}_component_router.rb")
|
17
|
-
routing_code = " component '#{name}'\n"
|
18
|
-
inject_into_file router_path, routing_code, after: rgx
|
19
|
-
end
|
20
|
-
|
21
|
-
private
|
22
|
-
|
23
|
-
def router_name
|
24
|
-
@options.fetch(:router, 'api')
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|