mega_scaffold 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 702f2689fb4ca9497026509a03ebf15fa89c1ced0e74835b1e9660e4d55780b9
4
+ data.tar.gz: d818c54ba05bb8d91090a0680b626a285a07a9e6cdcfc7e4047862ee53f3634b
5
+ SHA512:
6
+ metadata.gz: 4e15fa19562298c8dcad4cf7f70136e8aaeaad16baf5e15a186a4350de32a061174d854a8c675eb0f01d75c62798c2c9061f5638c69aed4dfe180359ff2f4b20
7
+ data.tar.gz: 710922460e48cc82c8873d259b336866ffa20986955c921d324246ad14b4381f84cec8b6a4077886361aae02b86340afb77458d7d1f9f0f5056c09bcd3bee0a4
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2022
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,146 @@
1
+ # mega_scaffold
2
+
3
+ This is the FASTEST way how to add CRUD functionality for your models. Literally by just adding ONE LINE of code in `routes.rb`.
4
+
5
+ With additional customization options it allows you to build quickly admin panels or simple controllers to output data.
6
+
7
+ It works with existing models so all your validations, associations, etc will work as usual.
8
+
9
+ ![rails scaffold generator](docs/mega_scaffold.png)
10
+
11
+ ## Usage
12
+
13
+ 1) add gem to Gemfile `gem "mega_scaffold"`
14
+
15
+ 2) open `routes.rb`
16
+
17
+ 3) add `mega_scaffold :categories` (if you have `Category` model)
18
+
19
+
20
+ ## Customization
21
+
22
+ - configure layout
23
+ - specify how to fetch records
24
+ - specify type for input
25
+ - configure to work with associations
26
+ - access helpers to output value
27
+ - hide columns
28
+ - change labels
29
+ - specify which fields where to show
30
+ - provide additional options for form fields
31
+
32
+ If you need examples of customization (see `test/dummy` as an example):
33
+
34
+ ```ruby
35
+ # routes.rb
36
+
37
+ Rails.application.routes.draw do
38
+
39
+ # could be nested in existing resources
40
+ resources :companies do
41
+ mega_scaffold :attachments,
42
+ parent: -> (controller) { Company.find(controller.params[:company_id]) },
43
+ collection: -> (controller) { controller.parent.attachments },
44
+ fields: [
45
+ { name: :id, view: :index },
46
+ { name: :file, type: :file_field, view: :all, value: -> (record, view) { view.link_to 'Download', record.file.url } },
47
+ { name: :created_at, view: :index },
48
+ ]
49
+ end
50
+
51
+ # could be added to namespaces
52
+ namespace :secret do
53
+ namespace :admin do
54
+ mega_scaffold :categories, fields: [
55
+ { name: :id, view: :index },
56
+ { name: :name, view: :all, value: -> (record, _) { record.name&.upcase } },
57
+ { name: :accounts, view: [:index, :show], value: -> (record, _) { record.accounts.count } },
58
+ { name: :created_at, view: [:index, :show], value: -> (record, _) { I18n.l record.created_at, format: :short } },
59
+ ]
60
+ end
61
+ end
62
+
63
+ # simple usage, you can specify concerns with "before_action" or other contoller-related logic
64
+ mega_scaffold :users,
65
+ collection: -> (_) { User.ordered },
66
+ concerns: [Protected],
67
+ layout: 'admin',
68
+ only: [:id, :name, :age, :dob, :country, :created_at, :phone]
69
+
70
+ # usage with file upload and showing images in the index and show views
71
+ mega_scaffold :photos,
72
+ fields: [
73
+ { name: :user, column: :user_id, view: :all, type: :select, collection: -> { User.by_name.map{|e| [e.name, e.id]} }, value: -> (record, view) { view.link_to_if record.user, record.user&.name, record.user } },
74
+ { name: :photo, type: :file_field, view: :all, value: -> (record, view) { view.image_tag record.photo.url, style: 'width: 200px' } },
75
+ { name: :created_at, view: :index, value: -> (record, view) { view.l record.created_at, format: :long } },
76
+ ]
77
+
78
+ # access to different set of records (for example admin can see all records and all other users only own) + form with associations
79
+ mega_scaffold :accounts,
80
+ collection: -> (controller) { controller.admin? ? Account.all : current_user.accounts },
81
+ fields: [
82
+ { name: :id, view: [:show] },
83
+ { name: :name, type: :text_field, view: :all, value: -> (record, view) { view.link_to record.name.to_s.upcase, record } },
84
+ {
85
+ view: :all,
86
+ name: :account_type,
87
+ type: :collection_select,
88
+ collection: -> { Account::TYPES },
89
+ options: [:to_s, :to_s, include_blank: true]
90
+ },
91
+ {
92
+ view: :all,
93
+ name: :priority,
94
+ type: :range_field,
95
+ options: { min: 0, max: 100, step: 10 }
96
+ },
97
+ {
98
+ name: :categories,
99
+ column: {
100
+ name: :category_ids,
101
+ permit: [],
102
+ },
103
+ type: :collection_check_boxes,
104
+ options: [:id, :name],
105
+ view: :form,
106
+ collection: -> { Category.by_name },
107
+ value: {
108
+ index: -> (record, _) { record.categories.count },
109
+ show: -> (record, _) { record.categories.pluck(:name).join(", ") }
110
+ }
111
+ },
112
+ { name: 'VIRTUAL ATTR', type: :virtual, view: :index, value: -> (record, view) { "ID: #{record.id}" } },
113
+ {
114
+ name: :owner_id,
115
+ label: "Owner",
116
+ view: :all,
117
+ options: { include_blank: true },
118
+ type: :select,
119
+ collection: -> { User.by_name.map{|e| [e.name, e.id]} },
120
+ value: -> (record, _) { record.owner&.name }
121
+ },
122
+ { name: :created_at, view: [:index, :show], value: -> (record, _) { I18n.l(record.created_at, format: :long) } },
123
+ ]
124
+ end
125
+ ```
126
+
127
+ ## TODO Ideas
128
+
129
+ - config for actions
130
+ - more specs
131
+ - simple search using ransack?
132
+ - how to overide view instructions
133
+ - check if all is ok with turbo/turbolinks
134
+ - export to CSV, JSON?
135
+ - integration with pundit or cancancan?
136
+ - support for "resource" type
137
+ - work with I18n to translate labels?
138
+ - how to customize views
139
+ - view customization per controller
140
+
141
+ ## Contributing
142
+
143
+ You are welcome to contribute.
144
+
145
+ ## License
146
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,3 @@
1
+ require "bundler/setup"
2
+
3
+ require "bundler/gem_tasks"
@@ -0,0 +1,48 @@
1
+ <style>
2
+ .mega_scaffold_container {
3
+ padding-top: 20px;
4
+ }
5
+
6
+ .mega_scaffold_container .mega_scaffold_container_header {
7
+ display: flex;
8
+ justify-content: space-between;
9
+ align-items: center;
10
+ }
11
+
12
+ .mega_scaffold_container .field_with_errors input,
13
+ .mega_scaffold_container .field_with_errors select,
14
+ .mega_scaffold_container .field_with_errors textarea {
15
+ border: 1px solid red;
16
+ }
17
+
18
+ .mega_scaffold_container abbr {
19
+ color: red;
20
+ text-decoration: none;
21
+ }
22
+
23
+ .mega_scaffold_container table {
24
+ width: 100%;
25
+ }
26
+
27
+ .mega_scaffold_container form .mega_scaffold_field_multiple label {
28
+ padding-left: 5px;
29
+ margin-right: 10px;
30
+ }
31
+
32
+ .mega_scaffold_container .pagination > * {
33
+ margin-right: 10px;
34
+ }
35
+
36
+ .mega_scaffold_container .mega_scaffold_errors {
37
+ font-size: 14px;
38
+ color: red;
39
+ }
40
+
41
+ .mega_scaffold_container .mega_scaffold_errors h4 {
42
+ font-size: 16px;
43
+ }
44
+
45
+ .mega_scaffold_container input[type=submit] {
46
+ cursor: pointer;
47
+ }
48
+ </style>
@@ -0,0 +1,64 @@
1
+ <%= form_for record, url: url_for(action: record.persisted? ? :update : :create, mega_scaffold.pk => record.send(mega_scaffold.pk)) , data: { turbo: false, turbolinks: false } do |f| %>
2
+ <% if record.errors.any? %>
3
+ <div class="mega_scaffold_errors">
4
+ <h4><%= pluralize(record.errors.count, "error") %> prohibited this record from being saved:</h4>
5
+ <ul>
6
+ <% record.errors.each do |error| %>
7
+ <li><%= error.full_message %></li>
8
+ <% end %>
9
+ </ul>
10
+ </div>
11
+ <% end %>
12
+
13
+ <% mega_scaffold.form.each do |e| %>
14
+ <% type = e[:type].presence || :text_field %>
15
+ <% field = e[:column].presence || e[:name] %>
16
+ <% field = field.is_a?(Hash) ? field[:name] : field %>
17
+ <% label = mega_scaffold_field_name(e) %>
18
+ <% options = e[:options].presence || {} rescue {} %>
19
+
20
+ <%# default %>
21
+ <% options.merge!({ rows: 4, cols: 60 }) if type == :text_area %>
22
+
23
+ <div class="mega_scaffold_field">
24
+ <% if type.to_s =~ /collection/ %>
25
+ <label><%= label %></label>
26
+ <div class="mega_scaffold_field_multiple">
27
+ <%= f.send type, field, e[:collection].call, *options %>
28
+ </div>
29
+
30
+ <% elsif type == :select %>
31
+ <label>
32
+ <%= label %>
33
+ <div>
34
+ <%= f.select field, e[:collection].call, options %>
35
+ </div>
36
+ </label>
37
+
38
+
39
+ <% elsif type == :check_box %>
40
+ <label>
41
+ <%= f.check_box field, options %>
42
+ <%= label %>
43
+ </label>
44
+
45
+
46
+ <% else %>
47
+ <label>
48
+ <%= label %>
49
+ <div>
50
+ <%= f.send type, field, options %>
51
+ </div>
52
+ </label>
53
+ <% end %>
54
+ </div>
55
+
56
+ <% end %>
57
+
58
+ <br>
59
+ <br>
60
+
61
+ <%= f.submit %>
62
+ &mdash;
63
+ <%= link_to 'Back', { action: :index } %>
64
+ <% end %>
@@ -0,0 +1,7 @@
1
+ <%= render 'mega_scaffold/css' %>
2
+
3
+ <div class="mega_scaffold_container">
4
+ <h1>Edit <%= mega_scaffold.model %></h1>
5
+
6
+ <%= render 'mega_scaffold/form', record: @record %>
7
+ </div>
@@ -0,0 +1,55 @@
1
+ <%= render 'mega_scaffold/css' %>
2
+
3
+ <div class="mega_scaffold_container">
4
+ <div class="mega_scaffold_container_header">
5
+ <h1><%= mega_scaffold.model.to_s.pluralize %></h1>
6
+ <div class="mega_scaffold_container_header_actions">
7
+ <%= link_to 'New', { action: :new }, { class: 'button btn btn-primary' } %>
8
+ <% if @parent %>
9
+ &mdash;
10
+ <%= link_to 'Back', mega_scaffold_parent_url %>
11
+ <% end %>
12
+ </div>
13
+ </div>
14
+
15
+ <table class="table">
16
+ <thead>
17
+ <tr>
18
+ <% mega_scaffold.columns.each do |field| %>
19
+ <th><%= mega_scaffold_field_name field %></th>
20
+ <% end %>
21
+ <th colspan="3"></th>
22
+ </tr>
23
+ </thead>
24
+
25
+ <tbody>
26
+ <% if @records.present? %>
27
+ <% @records.each do |record| %>
28
+ <tr>
29
+ <% mega_scaffold.columns.each do |field| %>
30
+ <td>
31
+ <%= mega_scaffold_value record, field, :index %>
32
+ </td>
33
+ <% end %>
34
+ <td><%= link_to 'show', { action: :show, mega_scaffold.pk => record.send(mega_scaffold.pk) } %></td>
35
+ <td><%= link_to 'edit', { action: :edit, mega_scaffold.pk => record.send(mega_scaffold.pk) } %></td>
36
+ <td><%= link_to 'delete', { action: :show, mega_scaffold.pk => record.send(mega_scaffold.pk) }, data: { method: :delete, turbo: false, turbolinks: false, confirm: "Are you sure?" } %></td>
37
+ </tr>
38
+ <% end %>
39
+ <% else %>
40
+ <tr>
41
+ <td colspan="<%= mega_scaffold.fields.size + 1 %>">
42
+ No Records.
43
+ </td>
44
+ </tr>
45
+ <% end %>
46
+ </tbody>
47
+
48
+ </table>
49
+
50
+ <% if respond_to?(:paginate) %>
51
+ <%= paginate @records %>
52
+ <% elsif respond_to?(:will_paginate) %>
53
+ <%= will_paginate @records %>
54
+ <% end %>
55
+ </div>
@@ -0,0 +1,7 @@
1
+ <%= render 'mega_scaffold/css' %>
2
+
3
+ <div class="mega_scaffold_container">
4
+ <h1>New <%= mega_scaffold.model %></h1>
5
+
6
+ <%= render 'mega_scaffold/form', record: @record %>
7
+ </div>
@@ -0,0 +1,18 @@
1
+ <%= render 'mega_scaffold/css' %>
2
+
3
+ <div class="mega_scaffold_container">
4
+ <h1><%= mega_scaffold.model %></h1>
5
+
6
+ <dl>
7
+ <% mega_scaffold.show.each do |field| %>
8
+ <dt><%= mega_scaffold_field_name field %>:</dt>
9
+ <dd>
10
+ <%= mega_scaffold_value @record, field %>
11
+ </dd>
12
+ <% end %>
13
+ </dl>
14
+
15
+ <%= link_to 'Edit', { action: :edit, mega_scaffold.pk => @record.send(mega_scaffold.pk) }, { class: 'button' } %>
16
+ -
17
+ <%= link_to 'Back', { action: :index }, { class: 'button' } %>
18
+ </div>
@@ -0,0 +1,77 @@
1
+ module MegaScaffold
2
+ class CodeGenerator
3
+ attr_reader :options
4
+
5
+ def initialize(options)
6
+ @options = options
7
+ end
8
+
9
+ def generate
10
+ strs = []
11
+ options[:namespaces].each_with_index do |e, index|
12
+ strs << "#{' ' * index}module #{index == 0 ? '::' + e : e}"
13
+ end
14
+
15
+ strs << %Q{
16
+ class #{'::' if options[:namespaces].empty?}#{options[:model].to_s.pluralize}Controller < ::ApplicationController
17
+ include MegaScaffold::Controller
18
+ include Helpers
19
+
20
+ #{"include " + options[:concerns].join(", ") if options[:concerns].any?}
21
+
22
+ helper :all
23
+
24
+ def parent
25
+ mega_scaffold.parent.call(self) if mega_scaffold.parent.is_a?(Proc)
26
+ end
27
+
28
+ def collection
29
+ mega_scaffold.collection.call(self)
30
+ end
31
+
32
+ def resource
33
+ collection.find(params[:id])
34
+ end
35
+
36
+ def find_parent
37
+ @parent = parent
38
+ end
39
+
40
+ private
41
+ def mega_scaffold
42
+ @mega_scaffold ||= OpenStruct.new({
43
+ scope: #{options[:scope][:as].to_s.to_json},
44
+ model: #{options[:model]},
45
+ pk: :#{options[:model].primary_key},
46
+ fields: self.class.fields_config,
47
+ columns: self.class.columns_config,
48
+ form: self.class.form_config,
49
+ show: self.class.show_config,
50
+ collection: self.class.collection_config,
51
+ parent: self.class.parent_config,
52
+ })
53
+ end
54
+
55
+ def detect_layout
56
+ "#{options[:layout].presence || 'application'}"
57
+ end
58
+ end
59
+ }
60
+
61
+ options[:namespaces].each_with_index do |e, index|
62
+ strs << "#{' ' * (options[:namespaces].size - index - 1)}end"
63
+ end
64
+
65
+ klass_name = "#{options[:namespaces].any? ? options[:namespaces].join("::") + "::" : '::'}#{options[:model].to_s.pluralize}Controller"
66
+ strs << klass_name
67
+
68
+ # delete old constant
69
+ # because it has conficts with same which was previosly initialized
70
+ # happend after changing routes.rb in dev mode
71
+ object_space = options[:namespaces].join("::").constantize rescue Object
72
+ object_space.send(:remove_const, :"#{options[:model].to_s.pluralize}Controller") rescue '='
73
+
74
+ strs.join("\n")
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,88 @@
1
+ module MegaScaffold
2
+ module Controller
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ prepend_view_path("#{MegaScaffold::Engine.root}/app/views")
7
+ before_action :find_parent
8
+ layout :detect_layout
9
+ helper_method :mega_scaffold
10
+ end
11
+
12
+ def index
13
+ @records = if defined?(Kaminari)
14
+ collection.page(params[:page])
15
+ elsif defined?(WillPaginate)
16
+ collection.paginate(params[:page])
17
+ else
18
+ collection
19
+ end
20
+ render template: 'mega_scaffold/index'
21
+ end
22
+
23
+ def show
24
+ @record = resource
25
+ render template: 'mega_scaffold/show'
26
+ end
27
+
28
+ def new
29
+ @record = collection.new
30
+ render template: 'mega_scaffold/new'
31
+ end
32
+
33
+ def create
34
+ @record = collection.build(record_params)
35
+ if @record.save
36
+ flash[:notice] = "#{mega_scaffold.model} successfully created"
37
+ redirect_to url_for({ action: :show, mega_scaffold.pk => @record.send(mega_scaffold.pk) })
38
+ else
39
+ render template: 'mega_scaffold/new', status: :unprocessable_entity
40
+ end
41
+ end
42
+
43
+ def edit
44
+ @record = resource
45
+ render template: 'mega_scaffold/edit'
46
+ end
47
+
48
+ def update
49
+ @record = resource
50
+ if @record.update(record_params)
51
+ flash[:notice] = "#{mega_scaffold.model} successfully updated"
52
+ redirect_to url_for({ action: :show, mega_scaffold.pk => @record.send(mega_scaffold.pk) })
53
+ else
54
+ render template: 'mega_scaffold/edit', status: :unprocessable_entity
55
+ end
56
+ end
57
+
58
+ def destroy
59
+ @record = resource
60
+ @record.destroy
61
+ flash[:notice] = "#{mega_scaffold.model} successfully deleted"
62
+ redirect_to action: :index
63
+ end
64
+
65
+ private
66
+
67
+ def mega_scaffold_permits
68
+ mega_scaffold.fields.map do |ee|
69
+ next if ee[:type] == :virtual
70
+ result = ee[:column].presence || ee[:name]
71
+ if result.is_a?(Hash)
72
+ if result[:permit]
73
+ { result[:name] => result[:permit] }
74
+ else
75
+ result[:name]
76
+ end
77
+ else
78
+ result
79
+ end
80
+ end.compact
81
+ end
82
+
83
+ def record_params
84
+ params.require(mega_scaffold.model.to_s.downcase).permit(mega_scaffold_permits)
85
+ end
86
+
87
+ end
88
+ end
@@ -0,0 +1,13 @@
1
+ module MegaScaffold
2
+ class Engine < ::Rails::Engine
3
+ isolate_namespace MegaScaffold
4
+
5
+ initializer 'mega_scaffold.helpers', before: :load_config_initializers do
6
+ ActiveSupport.on_load :action_view do
7
+ include MegaScaffold::Helpers
8
+ end
9
+ end
10
+
11
+ ActionDispatch::Routing::Mapper.send :include, MegaScaffold::Routing
12
+ end
13
+ end
@@ -0,0 +1,18 @@
1
+ module MegaScaffold
2
+ class FieldsGenerator
3
+ attr_reader :model
4
+
5
+ def initialize(model)
6
+ @model = model
7
+ end
8
+
9
+ def generate
10
+ model.columns.map do |e|
11
+ {
12
+ name: e.name,
13
+ type: MegaScaffold::TypeDetector.find_type(e),
14
+ }
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,23 @@
1
+ module MegaScaffold
2
+ module Helpers
3
+
4
+ def mega_scaffold_value(record, field, type = :show)
5
+ if field[:value].is_a?(Proc)
6
+ field[:value].call record, self
7
+ elsif field[:value].is_a?(Hash)
8
+ field[:value][type].call record, self
9
+ else
10
+ record.send(field[:name])
11
+ end
12
+ end
13
+
14
+ def mega_scaffold_field_name(field)
15
+ (field[:label].presence || field[:name]).to_s.titleize
16
+ end
17
+
18
+ def mega_scaffold_parent_url
19
+ [mega_scaffold.scope&.to_sym, @parent].reject(&:blank?)
20
+ end
21
+
22
+ end
23
+ end
@@ -0,0 +1,69 @@
1
+ module MegaScaffold
2
+ class KlassDecorator
3
+ attr_reader :klass, :options
4
+
5
+ def initialize(klass, options)
6
+ @klass = klass
7
+ @options = options
8
+ end
9
+
10
+ def decorate
11
+ # hack to have local variable available for define_method
12
+ local = options
13
+
14
+ klass.singleton_class.define_method :rules do
15
+ {
16
+ except: (Array.wrap(local[:except]) + Array.wrap(local[:ignore])).map(&:to_sym),
17
+ only: (Array.wrap(local[:only]) - Array.wrap(local[:ignore])).map(&:to_sym),
18
+ }
19
+ end
20
+
21
+ klass.singleton_class.define_method :fields_config do
22
+ local[:fields].map do |e|
23
+ e.merge({view: Array.wrap(e[:view]).map(&:to_sym)}).deep_symbolize_keys
24
+ end
25
+ end
26
+
27
+ klass.singleton_class.define_method :columns_config do
28
+ fields_config.select do |e|
29
+ next true if e[:view].empty?
30
+ next true if e[:view].include?(:index) || e[:view].include?(:all)
31
+
32
+ false
33
+ end
34
+ end
35
+
36
+ klass.singleton_class.define_method :form_config do
37
+ fields_config.select do |e|
38
+ next false if rules[:except].any? && rules[:except].include?(e[:name].to_sym)
39
+ next false if rules[:only].any? && !rules[:only].include?(e[:name].to_sym)
40
+
41
+ next true if e[:view].empty?
42
+ next true if e[:view].include?(:form) || e[:view].include?(:all)
43
+ false
44
+ end
45
+ end
46
+
47
+ klass.singleton_class.define_method :show_config do
48
+ fields_config.select do |e|
49
+ next true if e[:view].empty?
50
+ next true if e[:view].include?(:show) || e[:view].include?(:all)
51
+
52
+ false
53
+ end
54
+ end
55
+
56
+ klass.singleton_class.define_method :collection_config do
57
+ if local[:collection].is_a?(Proc)
58
+ local[:collection]
59
+ else
60
+ -> (controller) { local[:model].all }
61
+ end
62
+ end
63
+
64
+ klass.singleton_class.define_method :parent_config do
65
+ local[:parent]
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,47 @@
1
+ module MegaScaffold
2
+ module Routing
3
+
4
+ def mega_scaffold(*options,
5
+ fields: nil,
6
+ ignore: [:id, :created_at, :updated_at],
7
+ except: [],
8
+ only: [],
9
+ collection: nil,
10
+ parent: nil,
11
+ concerns: nil,
12
+ layout: "application"
13
+ )
14
+
15
+ model_name = options[0].to_s.singularize # user
16
+ model = model_name.classify.safe_constantize # User
17
+ concerns = Array.wrap(concerns)
18
+ return unless model
19
+
20
+ fields = MegaScaffold::FieldsGenerator.new(model).generate if fields.blank?
21
+ generator = MegaScaffold::CodeGenerator.new({
22
+ namespaces: @scope[:module].to_s.split("/").map{|e| e.classify},
23
+ concerns: concerns,
24
+ model: model,
25
+ scope: @scope,
26
+ layout: layout
27
+ })
28
+
29
+ klass = eval(generator.generate)
30
+
31
+ MegaScaffold::KlassDecorator.new(klass, {
32
+ fields: fields,
33
+ collection: collection,
34
+ parent: parent,
35
+ model: model,
36
+ except: except,
37
+ only: only,
38
+ ignore: ignore
39
+ }).decorate
40
+
41
+ resources *options
42
+ rescue ActiveRecord::StatementInvalid => ex
43
+ puts ex.message
44
+ end
45
+
46
+ end
47
+ end
@@ -0,0 +1,33 @@
1
+ module MegaScaffold
2
+ class TypeDetector
3
+ def TypeDetector.find_type(field)
4
+ case field.type
5
+ when :datetime
6
+ :datetime_field
7
+ when :date
8
+ :date_field
9
+ when :text
10
+ :text_area
11
+ when :boolean
12
+ :check_box
13
+ when :integer
14
+ :number_field
15
+ else
16
+ case field.name
17
+ when /password/
18
+ :password_field
19
+ when /phone/
20
+ :phone_field
21
+ when /email/
22
+ :email_field
23
+ when /color/
24
+ :color_field
25
+ when /url/
26
+ :url_field
27
+ else
28
+ :text_field
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,3 @@
1
+ module MegaScaffold
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,12 @@
1
+ require "mega_scaffold/version"
2
+ require "mega_scaffold/helpers"
3
+ require "mega_scaffold/controller"
4
+ require "mega_scaffold/fields_generator"
5
+ require "mega_scaffold/code_generator"
6
+ require "mega_scaffold/klass_decorator"
7
+ require "mega_scaffold/type_detector"
8
+ require "mega_scaffold/routing"
9
+ require "mega_scaffold/engine"
10
+
11
+ module MegaScaffold
12
+ end
metadata ADDED
@@ -0,0 +1,249 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mega_scaffold
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Igor Kasyanchuk
8
+ - Liubomyr Manastyretskyi
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2022-05-05 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rails
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ">="
19
+ - !ruby/object:Gem::Version
20
+ version: '0'
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ version: '0'
28
+ - !ruby/object:Gem::Dependency
29
+ name: puma
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: '0'
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ - !ruby/object:Gem::Dependency
43
+ name: pry
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ - !ruby/object:Gem::Dependency
57
+ name: sprockets-rails
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ - !ruby/object:Gem::Dependency
71
+ name: country_select
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ - !ruby/object:Gem::Dependency
85
+ name: sassc
86
+ requirement: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ type: :development
92
+ prerelease: false
93
+ version_requirements: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
98
+ - !ruby/object:Gem::Dependency
99
+ name: kaminari
100
+ requirement: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ version: '0'
105
+ type: :development
106
+ prerelease: false
107
+ version_requirements: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - ">="
110
+ - !ruby/object:Gem::Version
111
+ version: '0'
112
+ - !ruby/object:Gem::Dependency
113
+ name: faker
114
+ requirement: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - ">="
117
+ - !ruby/object:Gem::Version
118
+ version: '0'
119
+ type: :development
120
+ prerelease: false
121
+ version_requirements: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - ">="
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ - !ruby/object:Gem::Dependency
127
+ name: carrierwave
128
+ requirement: !ruby/object:Gem::Requirement
129
+ requirements:
130
+ - - ">="
131
+ - !ruby/object:Gem::Version
132
+ version: '0'
133
+ type: :development
134
+ prerelease: false
135
+ version_requirements: !ruby/object:Gem::Requirement
136
+ requirements:
137
+ - - ">="
138
+ - !ruby/object:Gem::Version
139
+ version: '0'
140
+ - !ruby/object:Gem::Dependency
141
+ name: rspec-rails
142
+ requirement: !ruby/object:Gem::Requirement
143
+ requirements:
144
+ - - ">="
145
+ - !ruby/object:Gem::Version
146
+ version: '0'
147
+ type: :development
148
+ prerelease: false
149
+ version_requirements: !ruby/object:Gem::Requirement
150
+ requirements:
151
+ - - ">="
152
+ - !ruby/object:Gem::Version
153
+ version: '0'
154
+ - !ruby/object:Gem::Dependency
155
+ name: simplecov
156
+ requirement: !ruby/object:Gem::Requirement
157
+ requirements:
158
+ - - ">="
159
+ - !ruby/object:Gem::Version
160
+ version: '0'
161
+ type: :development
162
+ prerelease: false
163
+ version_requirements: !ruby/object:Gem::Requirement
164
+ requirements:
165
+ - - ">="
166
+ - !ruby/object:Gem::Version
167
+ version: '0'
168
+ - !ruby/object:Gem::Dependency
169
+ name: wrapped_print
170
+ requirement: !ruby/object:Gem::Requirement
171
+ requirements:
172
+ - - ">="
173
+ - !ruby/object:Gem::Version
174
+ version: '0'
175
+ type: :development
176
+ prerelease: false
177
+ version_requirements: !ruby/object:Gem::Requirement
178
+ requirements:
179
+ - - ">="
180
+ - !ruby/object:Gem::Version
181
+ version: '0'
182
+ - !ruby/object:Gem::Dependency
183
+ name: ppp-util
184
+ requirement: !ruby/object:Gem::Requirement
185
+ requirements:
186
+ - - ">="
187
+ - !ruby/object:Gem::Version
188
+ version: '0'
189
+ type: :development
190
+ prerelease: false
191
+ version_requirements: !ruby/object:Gem::Requirement
192
+ requirements:
193
+ - - ">="
194
+ - !ruby/object:Gem::Version
195
+ version: '0'
196
+ description: Fastest way to add CRUD functionality to your Rails models. No jQuery
197
+ or other frontend dependencies.
198
+ email:
199
+ - igorkasyanchuk@gmail.com
200
+ - manastyretskyi@gmail.com
201
+ executables: []
202
+ extensions: []
203
+ extra_rdoc_files: []
204
+ files:
205
+ - MIT-LICENSE
206
+ - README.md
207
+ - Rakefile
208
+ - app/views/mega_scaffold/_css.html.erb
209
+ - app/views/mega_scaffold/_form.html.erb
210
+ - app/views/mega_scaffold/edit.html.erb
211
+ - app/views/mega_scaffold/index.html.erb
212
+ - app/views/mega_scaffold/new.html.erb
213
+ - app/views/mega_scaffold/show.html.erb
214
+ - lib/mega_scaffold.rb
215
+ - lib/mega_scaffold/code_generator.rb
216
+ - lib/mega_scaffold/controller.rb
217
+ - lib/mega_scaffold/engine.rb
218
+ - lib/mega_scaffold/fields_generator.rb
219
+ - lib/mega_scaffold/helpers.rb
220
+ - lib/mega_scaffold/klass_decorator.rb
221
+ - lib/mega_scaffold/routing.rb
222
+ - lib/mega_scaffold/type_detector.rb
223
+ - lib/mega_scaffold/version.rb
224
+ homepage: https://github.com/railsjazz/mega_scaffold
225
+ licenses:
226
+ - MIT
227
+ metadata:
228
+ homepage_uri: https://www.railsjazz.com/
229
+ source_code_uri: https://github.com/railsjazz/mega_scaffold
230
+ post_install_message:
231
+ rdoc_options: []
232
+ require_paths:
233
+ - lib
234
+ required_ruby_version: !ruby/object:Gem::Requirement
235
+ requirements:
236
+ - - ">="
237
+ - !ruby/object:Gem::Version
238
+ version: '0'
239
+ required_rubygems_version: !ruby/object:Gem::Requirement
240
+ requirements:
241
+ - - ">="
242
+ - !ruby/object:Gem::Version
243
+ version: '0'
244
+ requirements: []
245
+ rubygems_version: 3.2.3
246
+ signing_key:
247
+ specification_version: 4
248
+ summary: Fastest way to add CRUD functionality to your models.
249
+ test_files: []