kadim 0.2.3 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|