kadim 0.2.3 → 0.3.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 +53 -31
- data/app/assets/javascripts/kadim/application.js +3 -0
- data/app/assets/javascripts/kadim/direct_upload.js +36 -0
- data/app/assets/javascripts/kadim/resumable_upload.js +36 -0
- data/app/assets/stylesheets/kadim/direct_upload.css +37 -0
- data/app/assets/stylesheets/kadim/resumable_upload.css +37 -0
- data/app/controllers/kadim/application_controller.rb +6 -0
- data/app/helpers/kadim/application_helper.rb +34 -1
- data/lib/generators/kadim/scaffold_controller/USAGE +18 -0
- data/lib/generators/kadim/scaffold_controller/scaffold_controller_generator.rb +26 -0
- data/lib/generators/kadim/scaffold_controller/templates/_form.html.erb.tt +40 -0
- data/lib/kadim.rb +69 -25
- data/lib/kadim/engine.rb +3 -0
- data/lib/kadim/template/memory_resolver.rb +1 -0
- data/lib/kadim/version.rb +1 -1
- metadata +66 -13
- data/lib/generators/kadim/host/scaffold_controller/USAGE +0 -16
- data/lib/generators/kadim/host/scaffold_controller/scaffold_controller_generator.rb +0 -33
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cfb2766e697bcfdfec4e606aca5398f9f4ff673d3cd06daf91bc415609d3fe94
|
4
|
+
data.tar.gz: 1e2a9a1cc54e158157492e54db31b7391d31ab8cf5bbb96fc910198c3337a118
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 742c0dc9e953a303c4105e16bb5e9a32c41d19949046dd309f913071e9fdbfd806ac5f21df4793e84cc1273a8bda348eb3b56dda8e0fb34184f5277dfd406a7d
|
7
|
+
data.tar.gz: f9d5722c64dc28cac554d1bce33ad942e6fc9140e9b0189191556852fc6d20d2868f62f133899bf674b436a773136c012015aa83c7abc11a136b4c5a64ad2df2
|
data/README.md
CHANGED
@@ -1,48 +1,70 @@
|
|
1
1
|
# kadim*
|
2
2
|
Admin is all about CRUD, right?
|
3
3
|
|
4
|
-
My biggest experience with admins is with RailsAdmin. I currently work with an
|
5
|
-
it and all my peers hate having to customize anything on it, me too!
|
4
|
+
My biggest experience with admins is with [RailsAdmin](https://github.com/sferik/rails_admin). I currently work with an
|
5
|
+
application that makes extensive use of it and all my peers hate having to customize anything on it, me too!
|
6
6
|
|
7
|
-
|
8
|
-
|
7
|
+
I also tried [administrate](https://github.com/thoughtbot/administrate) and
|
8
|
+
[trestle](https://github.com/TrestleAdmin/trestle), I think they are a move forward, but reinventing the wheel is super
|
9
|
+
cool, right? The true is that I want more Rails and less DSL.
|
9
10
|
|
10
|
-
|
11
|
-
practice.
|
12
|
-
|
13
|
-
** kadim: derived from "cadim", an expression from the brazillian mineiro dialect that means "a little bit".*
|
11
|
+
**kadim: derived from "cadim", an expression from the brazillian mineiro dialect that means "a little bit".*
|
14
12
|
|
15
13
|
## Usage
|
16
|
-
In the current incarnation, it's very crud (no pun intended)
|
17
|
-
|
14
|
+
In the current incarnation, it's very crud (no pun intended). We just dynamically scaffold_controller your models using
|
15
|
+
all it's attributes and ActiveStorage relations inside `tmp/kadim` and load everything in memory, including views. This
|
16
|
+
allows you to run kadim in environments with ephemeral file systems, like [heroku](https://www.heroku.com/).
|
17
|
+
|
18
|
+
Just follow the [Installation](#installation) section and access http://localhost:3000/kadim
|
18
19
|
|
19
|
-
|
20
|
-
|
21
|
-
|
20
|
+
### ActiveStorage support
|
21
|
+
If we detect that you have S3, GCS or Azure Storage configured we will use
|
22
|
+
[Direct Uploads](https://edgeguides.rubyonrails.org/active_storage_overview.html#direct-uploads) by default. If you are
|
23
|
+
using GCS and uploading biiiig files, the `resumable` option is perfect:
|
22
24
|
|
23
|
-
|
24
|
-
|
25
|
+
```ruby
|
26
|
+
# config/initializers/kadim.rb
|
27
|
+
Kadim.configure do |config|
|
28
|
+
config.upload_type = :resumable
|
29
|
+
end
|
30
|
+
```
|
25
31
|
|
26
|
-
|
32
|
+
upload_type accepts the following options:
|
33
|
+
- :local - Uses ActiveStorage [Disk Service](https://edgeguides.rubyonrails.org/active_storage_overview.html#disk-service)
|
34
|
+
- :direct - Uses ActiveStorage [Direct Upload](https://edgeguides.rubyonrails.org/active_storage_overview.html#direct-uploads)
|
35
|
+
- :resumable - Uses [activestorage-resumable gem](https://rubygems.org/gems/activestorage-resumable) to implement [Resumable Uploads](https://cloud.google.com/storage/docs/performing-resumable-uploads) (supports only GCS)
|
27
36
|
|
28
|
-
|
29
|
-
this with the main kadim controller, to add safety rules, etc.
|
37
|
+
## Customization / generators
|
30
38
|
|
31
|
-
|
39
|
+
### kadim:host
|
32
40
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
41
|
+
Usage: `rails g kadim:host`
|
42
|
+
|
43
|
+
Hosts the base files of kadim inside your application, allowing you to customize from the base controller to the
|
44
|
+
layouts with the Ruby on Rails you know and love.
|
45
|
+
|
46
|
+
The following folders will be copied recursively to your application:
|
47
|
+
- app/assets/javascripts/kadim
|
48
|
+
- app/assets/stylesheets/kadim
|
49
|
+
- app/controllers/kadim
|
50
|
+
- app/helpers/kadim
|
51
|
+
- app/views/kadim
|
52
|
+
- app/views/layouts/kadim
|
53
|
+
|
54
|
+
It's pretty simple stuff, just take a look: https://github.com/fnix/kadim/tree/master/app
|
55
|
+
|
56
|
+
### kadim:scaffold_controller
|
57
|
+
|
58
|
+
Usage: `rails g kadim:scaffold_controller NAME [field:type field:type] [options]`
|
37
59
|
|
38
|
-
|
39
|
-
|
40
|
-
[main view](app/views/kadim/application/index.html.erb) and its [layout](app/views/layouts/kadim/application.html.erb),
|
41
|
-
a [helper](app/helpers/kadim/application_helper.rb) and [assets](app/assets/).
|
60
|
+
Hosts on your application the files generated in runtime by `kadim` for the giving resource. This generator is a thin
|
61
|
+
layer over the Rails scaffold_controller and accepts the same arguments.
|
42
62
|
|
43
|
-
|
44
|
-
|
45
|
-
|
63
|
+
For example, using `credit_card` for NAME, the following files wil be generated on your application:
|
64
|
+
- Controller: app/controllers/kadim/credit_cards_controller.rb
|
65
|
+
- Test: test/controllers/kadim/credit_cards_controller_test.rb
|
66
|
+
- Views: app/views/kadim/credit_cards/index.html.erb [...]
|
67
|
+
- Helper: app/helpers/kadim/credit_cards_helper.rb
|
46
68
|
|
47
69
|
## Installation
|
48
70
|
Add this line to your application's Gemfile:
|
@@ -71,7 +93,7 @@ And access http://localhost:3000/kadim
|
|
71
93
|
## Roadmap
|
72
94
|
- [x] Dynamic CRUD generation from application models
|
73
95
|
- [x] Tasks to copy files form kadim to the hosted application
|
74
|
-
- [
|
96
|
+
- [x] Add support to ActiveStorage attachments
|
75
97
|
- [ ] Add support to belongs_to relationships
|
76
98
|
- [ ] Add a beautiful look and feel
|
77
99
|
|
@@ -0,0 +1,36 @@
|
|
1
|
+
addEventListener('direct-upload:initialize', event => {
|
2
|
+
const { target, detail } = event
|
3
|
+
const { id, file } = detail
|
4
|
+
target.insertAdjacentHTML('beforebegin', `
|
5
|
+
<div id="direct-upload-${id}" class="direct-upload direct-upload--pending">
|
6
|
+
<div id="direct-upload-progress-${id}" class="direct-upload__progress" style="width: 0%"></div>
|
7
|
+
<span class="direct-upload__filename">${file.name}</span>
|
8
|
+
</div>
|
9
|
+
`)
|
10
|
+
})
|
11
|
+
|
12
|
+
addEventListener('direct-upload:start', event => {
|
13
|
+
const { id } = event.detail
|
14
|
+
const element = document.getElementById(`direct-upload-${id}`)
|
15
|
+
element.classList.remove('direct-upload--pending')
|
16
|
+
})
|
17
|
+
|
18
|
+
addEventListener('direct-upload:progress', event => {
|
19
|
+
const { id, progress } = event.detail
|
20
|
+
const progressElement = document.getElementById(`direct-upload-progress-${id}`)
|
21
|
+
progressElement.style.width = `${progress}%`
|
22
|
+
})
|
23
|
+
|
24
|
+
addEventListener('direct-upload:error', event => {
|
25
|
+
event.preventDefault()
|
26
|
+
const { id, error } = event.detail
|
27
|
+
const element = document.getElementById(`direct-upload-${id}`)
|
28
|
+
element.classList.add('direct-upload--error')
|
29
|
+
element.setAttribute('title', error)
|
30
|
+
})
|
31
|
+
|
32
|
+
addEventListener('direct-upload:end', event => {
|
33
|
+
const { id } = event.detail
|
34
|
+
const element = document.getElementById(`direct-upload-${id}`)
|
35
|
+
element.classList.add('direct-upload--complete')
|
36
|
+
})
|
@@ -0,0 +1,36 @@
|
|
1
|
+
addEventListener('resumable-upload:initialize', event => {
|
2
|
+
const { target, detail } = event
|
3
|
+
const { id, file } = detail
|
4
|
+
target.insertAdjacentHTML('beforebegin', `
|
5
|
+
<div id="resumable-upload-${id}" class="resumable-upload resumable-upload--pending">
|
6
|
+
<div id="resumable-upload-progress-${id}" class="resumable-upload__progress" style="width: 0%"></div>
|
7
|
+
<span class="resumable-upload__filename">${file.name}</span>
|
8
|
+
</div>
|
9
|
+
`)
|
10
|
+
})
|
11
|
+
|
12
|
+
addEventListener('resumable-upload:start', event => {
|
13
|
+
const { id } = event.detail
|
14
|
+
const element = document.getElementById(`resumable-upload-${id}`)
|
15
|
+
element.classList.remove('resumable-upload--pending')
|
16
|
+
})
|
17
|
+
|
18
|
+
addEventListener('resumable-upload:progress', event => {
|
19
|
+
const { id, progress } = event.detail
|
20
|
+
const progressElement = document.getElementById(`resumable-upload-progress-${id}`)
|
21
|
+
progressElement.style.width = `${progress}%`
|
22
|
+
})
|
23
|
+
|
24
|
+
addEventListener('resumable-upload:error', event => {
|
25
|
+
event.preventDefault()
|
26
|
+
const { id, error } = event.detail
|
27
|
+
const element = document.getElementById(`resumable-upload-${id}`)
|
28
|
+
element.classList.add('resumable-upload--error')
|
29
|
+
element.setAttribute('title', error)
|
30
|
+
})
|
31
|
+
|
32
|
+
addEventListener('resumable-upload:end', event => {
|
33
|
+
const { id } = event.detail
|
34
|
+
const element = document.getElementById(`resumable-upload-${id}`)
|
35
|
+
element.classList.add('resumable-upload--complete')
|
36
|
+
})
|
@@ -0,0 +1,37 @@
|
|
1
|
+
.direct-upload {
|
2
|
+
display: inline-block;
|
3
|
+
position: relative;
|
4
|
+
padding: 2px 4px;
|
5
|
+
margin: 0 3px 3px 0;
|
6
|
+
border: 1px solid rgba(0, 0, 0, 0.3);
|
7
|
+
border-radius: 3px;
|
8
|
+
font-size: 11px;
|
9
|
+
line-height: 13px;
|
10
|
+
}
|
11
|
+
|
12
|
+
.direct-upload--pending {
|
13
|
+
opacity: 0.6;
|
14
|
+
}
|
15
|
+
|
16
|
+
.direct-upload__progress {
|
17
|
+
position: absolute;
|
18
|
+
top: 0;
|
19
|
+
left: 0;
|
20
|
+
bottom: 0;
|
21
|
+
opacity: 0.2;
|
22
|
+
background: #0076ff;
|
23
|
+
transition: width 120ms ease-out, opacity 60ms 60ms ease-in;
|
24
|
+
transform: translate3d(0, 0, 0);
|
25
|
+
}
|
26
|
+
|
27
|
+
.direct-upload--complete .direct-upload__progress {
|
28
|
+
opacity: 0.4;
|
29
|
+
}
|
30
|
+
|
31
|
+
.direct-upload--error {
|
32
|
+
border-color: red;
|
33
|
+
}
|
34
|
+
|
35
|
+
input[type=file][data-direct-upload-url][disabled] {
|
36
|
+
display: none;
|
37
|
+
}
|
@@ -0,0 +1,37 @@
|
|
1
|
+
.resumable-upload {
|
2
|
+
display: inline-block;
|
3
|
+
position: relative;
|
4
|
+
padding: 2px 4px;
|
5
|
+
margin: 0 3px 3px 0;
|
6
|
+
border: 1px solid rgba(0, 0, 0, 0.3);
|
7
|
+
border-radius: 3px;
|
8
|
+
font-size: 11px;
|
9
|
+
line-height: 13px;
|
10
|
+
}
|
11
|
+
|
12
|
+
.resumable-upload--pending {
|
13
|
+
opacity: 0.6;
|
14
|
+
}
|
15
|
+
|
16
|
+
.resumable-upload__progress {
|
17
|
+
position: absolute;
|
18
|
+
top: 0;
|
19
|
+
left: 0;
|
20
|
+
bottom: 0;
|
21
|
+
opacity: 0.2;
|
22
|
+
background: #0076ff;
|
23
|
+
transition: width 120ms ease-out, opacity 60ms 60ms ease-in;
|
24
|
+
transform: translate3d(0, 0, 0);
|
25
|
+
}
|
26
|
+
|
27
|
+
.resumable-upload--complete .resumable-upload__progress {
|
28
|
+
opacity: 0.4;
|
29
|
+
}
|
30
|
+
|
31
|
+
.resumable-upload--error {
|
32
|
+
border-color: red;
|
33
|
+
}
|
34
|
+
|
35
|
+
input[type=file][data-resumable-upload-url][disabled] {
|
36
|
+
display: none;
|
37
|
+
}
|
@@ -3,6 +3,12 @@
|
|
3
3
|
module Kadim
|
4
4
|
class ApplicationController < ActionController::Base
|
5
5
|
protect_from_forgery with: :exception
|
6
|
+
before_action :import_main_app_polymorphic_mappings
|
6
7
|
append_view_path Kadim::MemoryResolver.instance
|
8
|
+
|
9
|
+
private
|
10
|
+
def import_main_app_polymorphic_mappings
|
11
|
+
Kadim::Engine.routes.polymorphic_mappings.merge! Rails.application.routes.polymorphic_mappings
|
12
|
+
end
|
7
13
|
end
|
8
14
|
end
|
@@ -3,10 +3,43 @@
|
|
3
3
|
module Kadim
|
4
4
|
module ApplicationHelper
|
5
5
|
def menu_links
|
6
|
+
kadim_link = link_to("Kadim", kadim.root_path)
|
6
7
|
links = Kadim.app_model_paths.map(&:camelize).map(&:constantize).map do |model_klass|
|
7
8
|
link_to model_klass.model_name.human(count: :many), model_klass
|
8
9
|
end
|
9
|
-
safe_join(links, " | ")
|
10
|
+
safe_join([kadim_link] + links, " | ")
|
11
|
+
end
|
12
|
+
|
13
|
+
def upload_type
|
14
|
+
case Kadim.upload_type
|
15
|
+
when :direct then { direct_upload: true }
|
16
|
+
when :resumable then { resumable_upload: true }
|
17
|
+
else {}
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def method_missing(method, *args, &block)
|
22
|
+
if method.to_s.end_with?("_path", "_url")
|
23
|
+
if main_app.respond_to?(method)
|
24
|
+
main_app.send(method, *args)
|
25
|
+
else
|
26
|
+
super
|
27
|
+
end
|
28
|
+
else
|
29
|
+
super
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def respond_to?(method)
|
34
|
+
if method.to_s.end_with?("_path", "_url")
|
35
|
+
if main_app.respond_to?(method)
|
36
|
+
true
|
37
|
+
else
|
38
|
+
super
|
39
|
+
end
|
40
|
+
else
|
41
|
+
super
|
42
|
+
end
|
10
43
|
end
|
11
44
|
end
|
12
45
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
Usage:
|
2
|
+
rails generate kadim:host:scaffold_controller NAME [field:type field:type] [options]
|
3
|
+
|
4
|
+
Description:
|
5
|
+
This is a thin wrapper on scaffold_controller from Rails, if you don't specify any field the generated scaffold will
|
6
|
+
contain all model fields, except id and timestamps.
|
7
|
+
|
8
|
+
Please, use rails generate scaffold_controller --help to see all options.
|
9
|
+
|
10
|
+
Example:
|
11
|
+
`rails generate kadim:host:scaffold_controller CreditCard`
|
12
|
+
|
13
|
+
This will create:
|
14
|
+
Credit card controller with URLs like /credit_cards.
|
15
|
+
Controller: app/controllers/credit_cards_controller.rb
|
16
|
+
Test: test/controllers/credit_cards_controller_test.rb
|
17
|
+
Views: app/views/credit_cards/index.html.erb [...]
|
18
|
+
Helper: app/helpers/credit_cards_helper.rb
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kadim
|
4
|
+
module Generators
|
5
|
+
class ScaffoldControllerGenerator < Rails::Generators::NamedBase
|
6
|
+
def initialize(args = [], local_options = {}, config = {})
|
7
|
+
@initial_args = args
|
8
|
+
@initial_options = local_options
|
9
|
+
@initial_config = config
|
10
|
+
super
|
11
|
+
end
|
12
|
+
|
13
|
+
def scaffold_controller
|
14
|
+
model_path = name.underscore
|
15
|
+
unless Kadim.app_model_paths.include?(model_path)
|
16
|
+
puts "Are you sure \"#{name}\" is a model?"
|
17
|
+
return
|
18
|
+
end
|
19
|
+
|
20
|
+
@initial_args += Kadim.scaffold_attributes(model_path.camelize.constantize) if @initial_args.one?
|
21
|
+
|
22
|
+
Kadim.scaffold_controller(@initial_args, @initial_options, @initial_config)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
<%%= form_with(model: <%= model_resource_name %>, local: true) do |form| %>
|
2
|
+
<%% if <%= singular_table_name %>.errors.any? %>
|
3
|
+
<div id="error_explanation">
|
4
|
+
<h2><%%= pluralize(<%= singular_table_name %>.errors.count, "error") %> prohibited this <%= singular_table_name %> from being saved:</h2>
|
5
|
+
|
6
|
+
<ul>
|
7
|
+
<%% <%= singular_table_name %>.errors.full_messages.each do |message| %>
|
8
|
+
<li><%%= message %></li>
|
9
|
+
<%% end %>
|
10
|
+
</ul>
|
11
|
+
</div>
|
12
|
+
<%% end %>
|
13
|
+
|
14
|
+
<% attributes.each do |attribute| -%>
|
15
|
+
<div class="field">
|
16
|
+
<% if attribute.password_digest? -%>
|
17
|
+
<%%= form.label :password %>
|
18
|
+
<%%= form.password_field :password %>
|
19
|
+
</div>
|
20
|
+
|
21
|
+
<div class="field">
|
22
|
+
<%%= form.label :password_confirmation %>
|
23
|
+
<%%= form.password_field :password_confirmation %>
|
24
|
+
<% elsif attribute.attachment? -%>
|
25
|
+
<%%= form.label :<%= attribute.column_name %> %>
|
26
|
+
<%%= form.<%= attribute.field_type %> :<%= attribute.column_name %>, **upload_type %>
|
27
|
+
<% elsif attribute.attachments? -%>
|
28
|
+
<%%= form.label :<%= attribute.column_name %> %>
|
29
|
+
<%%= form.<%= attribute.field_type %> :<%= attribute.column_name %>, **upload_type, multiple: true %>
|
30
|
+
<% else -%>
|
31
|
+
<%%= form.label :<%= attribute.column_name %> %>
|
32
|
+
<%%= form.<%= attribute.field_type %> :<%= attribute.column_name %> %>
|
33
|
+
<% end -%>
|
34
|
+
</div>
|
35
|
+
|
36
|
+
<% end -%>
|
37
|
+
<div class="actions">
|
38
|
+
<%%= form.submit %>
|
39
|
+
</div>
|
40
|
+
<%% end %>
|
data/lib/kadim.rb
CHANGED
@@ -4,6 +4,29 @@ require "kadim/engine"
|
|
4
4
|
require "kadim/template/memory_resolver"
|
5
5
|
|
6
6
|
module Kadim
|
7
|
+
# @overload upload_type
|
8
|
+
# @return [Symbol] current upload type used to scaffold file input fields
|
9
|
+
# @overload upload_type=(value)
|
10
|
+
# You can use the following symbols to set the upload type:
|
11
|
+
# * +:local+ - Uses ActiveStorage {https://guides.rubyonrails.org/active_storage_overview.html#disk-service Disk Service}
|
12
|
+
# * +:direct+ - Uses ActiveStorage {https://guides.rubyonrails.org/active_storage_overview.html#direct-uploads Direct Upload}
|
13
|
+
# * +:resumable+ - Uses {https://rubygems.org/gems/activestorage-resumable activestorage-resumable gem} to implement {https://cloud.google.com/storage/docs/performing-resumable-uploads Resumable Uploads} (supports only GCS)
|
14
|
+
# @param value [Symbol]
|
15
|
+
# @return [Symbol]
|
16
|
+
mattr_accessor :upload_type
|
17
|
+
|
18
|
+
def self.init
|
19
|
+
@@upload_type ||= if [:amazon, :google, :microsoft].include?(Rails.configuration.active_storage.service)
|
20
|
+
:direct
|
21
|
+
else
|
22
|
+
:local
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.configure
|
27
|
+
yield self
|
28
|
+
end
|
29
|
+
|
7
30
|
def self.app_model_paths
|
8
31
|
return [] unless db_connection?
|
9
32
|
|
@@ -22,13 +45,25 @@ module Kadim
|
|
22
45
|
scaffold_controllers
|
23
46
|
end
|
24
47
|
|
48
|
+
def self.scaffold_controller(args, options, config)
|
49
|
+
current_namespace = Rails::Generators.namespace
|
50
|
+
Rails::Generators.namespace = Kadim
|
51
|
+
|
52
|
+
require "rails/generators/erb/scaffold/scaffold_generator"
|
53
|
+
Erb::Generators::ScaffoldGenerator.source_paths.prepend(
|
54
|
+
File.expand_path("generators/kadim/scaffold_controller/templates", __dir__)
|
55
|
+
)
|
56
|
+
|
57
|
+
generator = Rails::Generators::ScaffoldControllerGenerator.new(args, options, config)
|
58
|
+
source_path_idx = generator.class.source_paths.index { |source_path| source_path.include?("jbuilder") }
|
59
|
+
generator.class.source_paths[source_path_idx] = generator.class.source_root if source_path_idx
|
60
|
+
generator.invoke_all
|
61
|
+
ensure
|
62
|
+
Rails::Generators.namespace = current_namespace
|
63
|
+
end
|
64
|
+
|
25
65
|
def self.scaffold_attributes(model_klass)
|
26
|
-
model_klass
|
27
|
-
.reject { |column| %w[id created_at updated_at].include?(column.name) }
|
28
|
-
.sort_by(&:name)
|
29
|
-
.map { |column| [column.name, column.type] }
|
30
|
-
.to_h
|
31
|
-
.map { |k, v| "#{k}:#{v}" }
|
66
|
+
database_attributes(model_klass) + attachment_attributes(model_klass)
|
32
67
|
end
|
33
68
|
|
34
69
|
class << self
|
@@ -58,31 +93,41 @@ module Kadim
|
|
58
93
|
Rails.application.load_generators
|
59
94
|
require "rails/generators/rails/scaffold_controller/scaffold_controller_generator"
|
60
95
|
|
61
|
-
current_namespace = Rails::Generators.namespace
|
62
|
-
Rails::Generators.namespace = Kadim
|
63
96
|
app_model_paths.each do |model_name|
|
64
97
|
next if Kadim.const_defined?("#{model_name.pluralize}_controller".camelize, false)
|
98
|
+
model_klass = model_name.camelize.constantize
|
99
|
+
return unless model_klass.table_exists?
|
100
|
+
|
101
|
+
args = [model_name, *scaffold_attributes(model_klass)]
|
102
|
+
options = ["--force", "--quiet", "--no-test-framework", "--no-helper", "--template-engine=erb"]
|
103
|
+
config = { destination_root: Rails.root.join("tmp", "kadim") }
|
65
104
|
|
66
|
-
scaffold_controller(
|
105
|
+
scaffold_controller(args, options, config)
|
67
106
|
end
|
68
107
|
load_kadim_controllers
|
69
108
|
load_kadim_views
|
70
|
-
ensure
|
71
|
-
Rails::Generators.namespace = current_namespace
|
72
109
|
end
|
73
110
|
|
74
|
-
def
|
75
|
-
model_klass
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
111
|
+
def database_attributes(model_klass)
|
112
|
+
model_klass.columns
|
113
|
+
.reject { |column| %w[id created_at updated_at].include?(column.name) }
|
114
|
+
.sort_by(&:name)
|
115
|
+
.map { |column| [column.name, column.type] }
|
116
|
+
.to_h
|
117
|
+
.map { |k, v| "#{k}:#{v}" }
|
118
|
+
end
|
119
|
+
|
120
|
+
def attachment_attributes(model_klass)
|
121
|
+
model_klass.attachment_reflections
|
122
|
+
.values
|
123
|
+
.map do |reflection|
|
124
|
+
attribute_type = if reflection.is_a?(ActiveStorage::Reflection::HasOneAttachedReflection)
|
125
|
+
"attachment"
|
126
|
+
else
|
127
|
+
"attachments"
|
128
|
+
end
|
129
|
+
"#{reflection.name}:#{attribute_type}"
|
130
|
+
end
|
86
131
|
end
|
87
132
|
|
88
133
|
def load_kadim_controllers
|
@@ -105,8 +150,7 @@ module Kadim
|
|
105
150
|
end
|
106
151
|
|
107
152
|
def db_connection?
|
108
|
-
ActiveRecord::Base.
|
109
|
-
ActiveRecord::Base.connection # Calls connection object
|
153
|
+
ActiveRecord::Base.connection
|
110
154
|
ActiveRecord::Base.connected?
|
111
155
|
rescue ActiveRecord::AdapterNotFound, ActiveRecord::AdapterNotSpecified, ActiveRecord::NoDatabaseError
|
112
156
|
false
|
data/lib/kadim/engine.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "activestorage/resumable"
|
4
|
+
|
3
5
|
module Kadim
|
4
6
|
class Engine < ::Rails::Engine
|
5
7
|
isolate_namespace Kadim
|
@@ -12,6 +14,7 @@ module Kadim
|
|
12
14
|
end
|
13
15
|
|
14
16
|
config.to_prepare do
|
17
|
+
Kadim.init
|
15
18
|
Kadim.bootstrap_controllers
|
16
19
|
end
|
17
20
|
|
@@ -53,6 +53,7 @@ module Kadim
|
|
53
53
|
|
54
54
|
private
|
55
55
|
def find_templates(name, prefix, partial, details, locals = [])
|
56
|
+
details[:handlers].map! { |handler| handler.to_sym }
|
56
57
|
return unless details[:formats].include?(:html) && details[:handlers].include?(:erb)
|
57
58
|
|
58
59
|
body = @store.find(name, prefix, partial)
|
data/lib/kadim/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kadim
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kadu Diógenes
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-12-
|
11
|
+
date: 2019-12-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activestorage-resumable
|
@@ -24,6 +24,26 @@ dependencies:
|
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: 1.0.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: google-cloud-storage
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.21.0
|
34
|
+
- - "<"
|
35
|
+
- !ruby/object:Gem::Version
|
36
|
+
version: '2.0'
|
37
|
+
type: :runtime
|
38
|
+
prerelease: false
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 1.21.0
|
44
|
+
- - "<"
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '2.0'
|
27
47
|
- !ruby/object:Gem::Dependency
|
28
48
|
name: rails
|
29
49
|
requirement: !ruby/object:Gem::Requirement
|
@@ -66,6 +86,20 @@ dependencies:
|
|
66
86
|
- - "~>"
|
67
87
|
- !ruby/object:Gem::Version
|
68
88
|
version: 0.9.4
|
89
|
+
- !ruby/object:Gem::Dependency
|
90
|
+
name: guard-rspec
|
91
|
+
requirement: !ruby/object:Gem::Requirement
|
92
|
+
requirements:
|
93
|
+
- - "~>"
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: 4.7.3
|
96
|
+
type: :development
|
97
|
+
prerelease: false
|
98
|
+
version_requirements: !ruby/object:Gem::Requirement
|
99
|
+
requirements:
|
100
|
+
- - "~>"
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: 4.7.3
|
69
103
|
- !ruby/object:Gem::Dependency
|
70
104
|
name: guard
|
71
105
|
requirement: !ruby/object:Gem::Requirement
|
@@ -81,19 +115,19 @@ dependencies:
|
|
81
115
|
- !ruby/object:Gem::Version
|
82
116
|
version: 2.16.1
|
83
117
|
- !ruby/object:Gem::Dependency
|
84
|
-
name:
|
118
|
+
name: launchy
|
85
119
|
requirement: !ruby/object:Gem::Requirement
|
86
120
|
requirements:
|
87
121
|
- - "~>"
|
88
122
|
- !ruby/object:Gem::Version
|
89
|
-
version: 4.
|
123
|
+
version: 2.4.3
|
90
124
|
type: :development
|
91
125
|
prerelease: false
|
92
126
|
version_requirements: !ruby/object:Gem::Requirement
|
93
127
|
requirements:
|
94
128
|
- - "~>"
|
95
129
|
- !ruby/object:Gem::Version
|
96
|
-
version: 4.
|
130
|
+
version: 2.4.3
|
97
131
|
- !ruby/object:Gem::Dependency
|
98
132
|
name: nokogiri
|
99
133
|
requirement: !ruby/object:Gem::Requirement
|
@@ -151,33 +185,33 @@ dependencies:
|
|
151
185
|
- !ruby/object:Gem::Version
|
152
186
|
version: 2.0.3
|
153
187
|
- !ruby/object:Gem::Dependency
|
154
|
-
name:
|
188
|
+
name: redcarpet
|
155
189
|
requirement: !ruby/object:Gem::Requirement
|
156
190
|
requirements:
|
157
191
|
- - "~>"
|
158
192
|
- !ruby/object:Gem::Version
|
159
|
-
version: 3.
|
193
|
+
version: 3.5.0
|
160
194
|
type: :development
|
161
195
|
prerelease: false
|
162
196
|
version_requirements: !ruby/object:Gem::Requirement
|
163
197
|
requirements:
|
164
198
|
- - "~>"
|
165
199
|
- !ruby/object:Gem::Version
|
166
|
-
version: 3.
|
200
|
+
version: 3.5.0
|
167
201
|
- !ruby/object:Gem::Dependency
|
168
|
-
name:
|
202
|
+
name: rspec-rails
|
169
203
|
requirement: !ruby/object:Gem::Requirement
|
170
204
|
requirements:
|
171
205
|
- - "~>"
|
172
206
|
- !ruby/object:Gem::Version
|
173
|
-
version:
|
207
|
+
version: 3.8.0
|
174
208
|
type: :development
|
175
209
|
prerelease: false
|
176
210
|
version_requirements: !ruby/object:Gem::Requirement
|
177
211
|
requirements:
|
178
212
|
- - "~>"
|
179
213
|
- !ruby/object:Gem::Version
|
180
|
-
version:
|
214
|
+
version: 3.8.0
|
181
215
|
- !ruby/object:Gem::Dependency
|
182
216
|
name: rubocop-performance
|
183
217
|
requirement: !ruby/object:Gem::Requirement
|
@@ -220,6 +254,20 @@ dependencies:
|
|
220
254
|
- - "~>"
|
221
255
|
- !ruby/object:Gem::Version
|
222
256
|
version: 1.36.0
|
257
|
+
- !ruby/object:Gem::Dependency
|
258
|
+
name: rubocop
|
259
|
+
requirement: !ruby/object:Gem::Requirement
|
260
|
+
requirements:
|
261
|
+
- - "~>"
|
262
|
+
- !ruby/object:Gem::Version
|
263
|
+
version: 0.72.0
|
264
|
+
type: :development
|
265
|
+
prerelease: false
|
266
|
+
version_requirements: !ruby/object:Gem::Requirement
|
267
|
+
requirements:
|
268
|
+
- - "~>"
|
269
|
+
- !ruby/object:Gem::Version
|
270
|
+
version: 0.72.0
|
223
271
|
- !ruby/object:Gem::Dependency
|
224
272
|
name: selenium-webdriver
|
225
273
|
requirement: !ruby/object:Gem::Requirement
|
@@ -274,7 +322,11 @@ files:
|
|
274
322
|
- Rakefile
|
275
323
|
- app/assets/config/kadim_manifest.js
|
276
324
|
- app/assets/javascripts/kadim/application.js
|
325
|
+
- app/assets/javascripts/kadim/direct_upload.js
|
326
|
+
- app/assets/javascripts/kadim/resumable_upload.js
|
277
327
|
- app/assets/stylesheets/kadim/application.css
|
328
|
+
- app/assets/stylesheets/kadim/direct_upload.css
|
329
|
+
- app/assets/stylesheets/kadim/resumable_upload.css
|
278
330
|
- app/controllers/kadim/application_controller.rb
|
279
331
|
- app/helpers/kadim/application_helper.rb
|
280
332
|
- app/jobs/kadim/application_job.rb
|
@@ -284,8 +336,9 @@ files:
|
|
284
336
|
- config/routes.rb
|
285
337
|
- lib/generators/kadim/host/USAGE
|
286
338
|
- lib/generators/kadim/host/host_generator.rb
|
287
|
-
- lib/generators/kadim/
|
288
|
-
- lib/generators/kadim/
|
339
|
+
- lib/generators/kadim/scaffold_controller/USAGE
|
340
|
+
- lib/generators/kadim/scaffold_controller/scaffold_controller_generator.rb
|
341
|
+
- lib/generators/kadim/scaffold_controller/templates/_form.html.erb.tt
|
289
342
|
- lib/kadim.rb
|
290
343
|
- lib/kadim/engine.rb
|
291
344
|
- lib/kadim/template/memory_resolver.rb
|
@@ -1,16 +0,0 @@
|
|
1
|
-
Description:
|
2
|
-
Hosts on your application the files generated in runtime by `kadim` for the giving resource. This turns the
|
3
|
-
responsability for the resource to your application.
|
4
|
-
|
5
|
-
The model attributes are automatically detected by `kadim`.
|
6
|
-
resource.
|
7
|
-
|
8
|
-
Example:
|
9
|
-
`rails generate kadim:host:scaffold_controller CreditCard`
|
10
|
-
|
11
|
-
This will create:
|
12
|
-
Credit card controller with URLs like /credit_cards.
|
13
|
-
Controller: app/controllers/credit_cards_controller.rb
|
14
|
-
Test: test/controllers/credit_cards_controller_test.rb
|
15
|
-
Views: app/views/credit_cards/index.html.erb [...]
|
16
|
-
Helper: app/helpers/credit_cards_helper.rb
|
@@ -1,33 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Kadim
|
4
|
-
module Host
|
5
|
-
class ScaffoldControllerGenerator < Rails::Generators::NamedBase
|
6
|
-
source_root File.expand_path("templates", __dir__)
|
7
|
-
|
8
|
-
def scaffold_controller
|
9
|
-
model_path = name.underscore
|
10
|
-
unless Kadim.app_model_paths.include?(model_path)
|
11
|
-
puts "Are you sure \"#{name}\" is a model?"
|
12
|
-
return
|
13
|
-
end
|
14
|
-
|
15
|
-
|
16
|
-
Rails::Generators.namespace = Kadim
|
17
|
-
generator = Rails::Generators::ScaffoldControllerGenerator.new(
|
18
|
-
[model_path, *Kadim.scaffold_attributes(model_path.camelize.constantize)],
|
19
|
-
["--no-jbuilder", "--template-engine=erb"],
|
20
|
-
behavior: behavior,
|
21
|
-
destination_root: destination_root
|
22
|
-
)
|
23
|
-
|
24
|
-
# jbuilder 2.9.1 controller template uses a method removed from Rails6
|
25
|
-
# https://github.com/rails/jbuilder/issues/470
|
26
|
-
source_path_idx = generator.class.source_paths.index { |source_path| source_path.include?("jbuilder") }
|
27
|
-
generator.class.source_paths[source_path_idx] = generator.class.source_root if source_path_idx
|
28
|
-
|
29
|
-
generator.invoke_all
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|