plutonium 0.5.0 → 0.6.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 +4 -4
- data/app/views/resource/index.html.erb +1 -1
- data/brakeman.ignore +0 -23
- data/lib/generators/pu/core/install/templates/config/initializers/plutonium.rb +1 -2
- data/lib/generators/pu/resource/model/templates/model.rb.tt +11 -11
- data/lib/generators/pu/rodauth/templates/app/models/account.rb.tt +3 -7
- data/lib/plutonium/core/app_controller.rb +2 -2
- data/lib/plutonium/core/controllers/authorizable.rb +8 -1
- data/lib/plutonium/core/controllers/crud_actions.rb +11 -13
- data/lib/plutonium/core/controllers/interactive_actions.rb +1 -0
- data/lib/plutonium/core/controllers/presentable.rb +4 -3
- data/lib/plutonium/core/fields/inputs/attachment_input.rb +24 -0
- data/lib/plutonium/core/fields/inputs/{basic_input.rb → base.rb} +4 -2
- data/lib/plutonium/core/fields/inputs/{belongs_to_input.rb → belongs_to_association_input.rb} +1 -1
- data/lib/plutonium/core/fields/inputs/factory.rb +7 -25
- data/lib/plutonium/core/fields/inputs/{has_many_input.rb → has_many_association_input.rb} +1 -1
- data/lib/plutonium/core/fields/inputs/{association_input.rb → simple_form_association_input.rb} +1 -1
- data/lib/plutonium/core/fields/inputs/simple_form_input.rb +11 -0
- data/lib/plutonium/core/fields/inputs.rb +6 -4
- data/lib/plutonium/core/fields/renderers/attachment_renderer.rb +28 -0
- data/lib/plutonium/core/fields/renderers/factory.rb +4 -18
- data/lib/plutonium/core/fields/renderers.rb +3 -2
- data/lib/plutonium/core/ui/collection.rb +2 -2
- data/lib/plutonium/helpers/attachment_helper.rb +22 -11
- data/lib/plutonium/helpers/form_helper.rb +2 -4
- data/lib/plutonium/policy/scope.rb +5 -5
- data/lib/plutonium/railtie.rb +12 -0
- data/lib/plutonium/reactor/core.rb +2 -0
- data/lib/plutonium/reactor/policy_context.rb +5 -0
- data/lib/plutonium/reactor/resource_context.rb +1 -11
- data/lib/plutonium/reactor/resource_controller.rb +28 -5
- data/lib/plutonium/reactor/resource_policy.rb +2 -2
- data/lib/plutonium/reactor/resource_presenter.rb +7 -2
- data/lib/plutonium/reactor/resource_record.rb +97 -35
- data/lib/plutonium/reactor.rb +1 -0
- data/lib/plutonium/simple_form_components/attachment_component.rb +9 -3
- data/lib/plutonium/simple_form_components/input_group_component.rb +1 -0
- data/lib/plutonium/version.rb +1 -1
- data/lib/plutonium.rb +1 -0
- metadata +11 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c8fb31a8eb4837634d28b3b0f602b06494991cdcdc02fc600888d0fecf8c497e
|
4
|
+
data.tar.gz: 4c62d88f641d1890785cac1f6bf483b78e334fd2646bf91b21b3a5a53bd20b2c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cdc10f0c4d1f23a8fe565968d674d41fd8f9ee0aa43b6a1007ac8bca40897d1f0ee48189230b6aa742d1df53c7055e57eee960a29f265cebeb18160d6b8b73c3
|
7
|
+
data.tar.gz: 745dfeb89b822d2ba1181050ad3a78de32084361a19664b2f8dc8ab3bbdbff87e4eebae40cec02ebeaed1b966654edab646d6b1570a29eb64147b557ff8d75d8
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
-
# Plutonium:
|
1
|
+
# Plutonium: Take Your Rails Productivity Nuclear🚀!
|
2
2
|
|
3
|
-
**Plutonium**
|
3
|
+
**Plutonium** picks up where Rails left off, introducing application level concepts and tooling, transforming the way you build applications with Rails.
|
4
4
|
It's a culmination of lessons learned from years of developing nearly identical applications and is designed to save you from the drudgery of re-implementation.
|
5
5
|
|
6
6
|
**Why Choose Plutonium?**
|
@@ -8,14 +8,14 @@ It's a culmination of lessons learned from years of developing nearly identical
|
|
8
8
|
- **Efficiency by Design:** Plutonium is built for developers who demand efficiency without compromise. It automates 90% of your application needs while giving you the flexibility to tailor the remaining 10% to your specific requirements.
|
9
9
|
- **Comprehensive Features:** From authentication and authorization to CRUD operations, and beyond, Plutonium covers a wide array of functionalities out of the box:
|
10
10
|
- Authentication & Authorization
|
11
|
-
- Complete CRUD operations with advanced features: customizable tables, forms, pagination, actions, search, filtering, and nested resources.
|
11
|
+
- Complete CRUD operations with advanced features: customizable inputs, fields, tables, forms, pagination, actions, search, filtering, and nested resources.
|
12
12
|
- Modular architecture leveraging Rails engines for improved packaging and namespacing.
|
13
13
|
- Time-saving generators for boilerplate tasks.
|
14
14
|
- **Omakase with a Twist:** Inspired by Rails' omakase philosophy, Plutonium delivers a convention-based approach but doesn't box you in. It's seamlessly integrated into your project, allowing you to write your application as you would with vanilla Rails but with powerful extensions.
|
15
15
|
- **MVC and Beyond:** Plutonium adopts the MVC pattern, enhanced with modern web technologies like [hotwire](TODO), to deliver an interactive and robust user experience. It emphasizes progressive enhancement, ensuring a smooth development process and end-user experience.
|
16
16
|
- **Rails Harmony:** A Plutonium app is a Rails app at its core. It respects and builds upon Rails' conventions, making it intuitive for Rails developers. If you know Rails, learning Plutonium requires only a few new concepts.
|
17
17
|
- **Effortless Customization:** Plutonium is designed for easy customization to meet your unique requirements. Whether adjusting the functionality of entire resource groups or fine-tuning individual elements, our accessible low-level APIs and the familiar Rails conventions offer unparalleled flexibility. This ensures that any modifications you need to make can be implemented swiftly and smoothly, reducing complexity and enhancing your development experience.
|
18
|
-
- **Community-Driven Dependencies:** Plutonium stands on the shoulders of giants, integrating with well-established gems
|
18
|
+
- **Community-Driven Dependencies:** Plutonium stands on the shoulders of giants, integrating with well-established gems chosen for their robustness and flexibility, including:
|
19
19
|
- [ActiveInteraction](https://github.com/AaronLasseigne/active_interaction) for business logic
|
20
20
|
- [Pagy](https://github.com/ddnexus/pagy) for pagination
|
21
21
|
- [Pundit](https://github.com/varvet/pundit) for authorization
|
data/brakeman.ignore
CHANGED
@@ -22,29 +22,6 @@
|
|
22
22
|
],
|
23
23
|
"note": "this is tested and confirmed to be a false flag"
|
24
24
|
},
|
25
|
-
{
|
26
|
-
"warning_type": "Mass Assignment",
|
27
|
-
"warning_code": 70,
|
28
|
-
"fingerprint": "873ee0d868e06a32e8ff387a38ddb8c6183a419813d5c20122fa9c3a887f4e54",
|
29
|
-
"check_name": "MassAssignment",
|
30
|
-
"message": "Specify exact keys allowed for mass assignment instead of using `permit!` which allows any keys",
|
31
|
-
"file": "lib/plutonium/reactor/resource_controller.rb",
|
32
|
-
"line": 58,
|
33
|
-
"link": "https://brakemanscanner.org/docs/warning_types/mass_assignment/",
|
34
|
-
"code": "params.require(resource_param_key).permit!",
|
35
|
-
"render_path": null,
|
36
|
-
"location": {
|
37
|
-
"type": "method",
|
38
|
-
"class": "Plutonium::Reactor::ResourceController",
|
39
|
-
"method": "resource_params"
|
40
|
-
},
|
41
|
-
"user_input": null,
|
42
|
-
"confidence": "Medium",
|
43
|
-
"cwe_id": [
|
44
|
-
915
|
45
|
-
],
|
46
|
-
"note": "we manually filter params"
|
47
|
-
}
|
48
25
|
],
|
49
26
|
"updated": "2024-02-18 00:37:39 +0000",
|
50
27
|
"brakeman_version": "6.1.2"
|
@@ -1,2 +1 @@
|
|
1
|
-
#
|
2
|
-
Plutonium::Reactor::Core.achieve_criticality!
|
1
|
+
# Configure plutonium here
|
@@ -25,17 +25,6 @@ class <%= class_name %> < <%= [feature_package_name, "ResourceRecord"].join "::"
|
|
25
25
|
<% end -%>
|
26
26
|
# add attachments above.
|
27
27
|
|
28
|
-
<% attributes.select(&:rich_text?).each do |attribute| -%>
|
29
|
-
has_rich_text :<%= attribute.name %>
|
30
|
-
<% end -%>
|
31
|
-
<% attributes.select(&:token?).each do |attribute| -%>
|
32
|
-
has_secure_token<% if attribute.name != "token" %> :<%= attribute.name %><% end %>
|
33
|
-
<% end -%>
|
34
|
-
<% if attributes.any?(&:password_digest?) -%>
|
35
|
-
has_secure_password
|
36
|
-
<% end -%>
|
37
|
-
# add misc attribute macros above.
|
38
|
-
|
39
28
|
# add scopes above.
|
40
29
|
|
41
30
|
<% attributes.select(&:required?).each do |attribute| -%>
|
@@ -48,6 +37,17 @@ class <%= class_name %> < <%= [feature_package_name, "ResourceRecord"].join "::"
|
|
48
37
|
|
49
38
|
# add delegations above.
|
50
39
|
|
40
|
+
<% attributes.select(&:rich_text?).each do |attribute| -%>
|
41
|
+
has_rich_text :<%= attribute.name %>
|
42
|
+
<% end -%>
|
43
|
+
<% attributes.select(&:token?).each do |attribute| -%>
|
44
|
+
has_secure_token<% if attribute.name != "token" %> :<%= attribute.name %><% end %>
|
45
|
+
<% end -%>
|
46
|
+
<% if attributes.any?(&:password_digest?) -%>
|
47
|
+
has_secure_password
|
48
|
+
<% end -%>
|
49
|
+
# add misc attribute macros above.
|
50
|
+
|
51
51
|
# add methods above.
|
52
52
|
end
|
53
53
|
<% end -%>
|
@@ -13,13 +13,6 @@ class <%= table_prefix.camelize %> < ApplicationRecord
|
|
13
13
|
|
14
14
|
# add attachments above.
|
15
15
|
|
16
|
-
<% if ActiveRecord.version >= Gem::Version.new("7.0") -%>
|
17
|
-
enum :status, unverified: 1, verified: 2, closed: 3
|
18
|
-
<% else -%>
|
19
|
-
enum status: { unverified: 1, verified: 2, closed: 3 }
|
20
|
-
<% end -%>
|
21
|
-
# add misc attribute macros above.
|
22
|
-
|
23
16
|
# add scopes above.
|
24
17
|
|
25
18
|
validates :email, presence: true
|
@@ -29,6 +22,9 @@ class <%= table_prefix.camelize %> < ApplicationRecord
|
|
29
22
|
|
30
23
|
# add delegations above.
|
31
24
|
|
25
|
+
enum :status, unverified: 1, verified: 2, closed: 3
|
26
|
+
# add misc attribute macros above.
|
27
|
+
|
32
28
|
# add methods above.
|
33
29
|
end
|
34
30
|
<% else -%>
|
@@ -11,9 +11,9 @@ module Plutonium
|
|
11
11
|
|
12
12
|
private
|
13
13
|
|
14
|
-
def resource_presenter(resource_class)
|
14
|
+
def resource_presenter(resource_class, resource_record)
|
15
15
|
presenter_class = "#{current_package}::#{resource_class}Presenter".constantize
|
16
|
-
presenter_class.new resource_context
|
16
|
+
presenter_class.new resource_context, resource_record
|
17
17
|
end
|
18
18
|
|
19
19
|
def policy_namespace(scope)
|
@@ -20,8 +20,15 @@ module Plutonium
|
|
20
20
|
raise NotImplementedError, "policy_namespace"
|
21
21
|
end
|
22
22
|
|
23
|
+
def policy_context
|
24
|
+
Plutonium::Reactor::PolicyContext.new(
|
25
|
+
user: current_user,
|
26
|
+
resource_context: resource_context
|
27
|
+
)
|
28
|
+
end
|
29
|
+
|
23
30
|
def pundit_user
|
24
|
-
|
31
|
+
policy_context
|
25
32
|
end
|
26
33
|
|
27
34
|
def policy(scope)
|
@@ -29,24 +29,12 @@ module Plutonium
|
|
29
29
|
authorize resource_class
|
30
30
|
|
31
31
|
@resource_record = resource_class.new
|
32
|
-
|
33
|
-
resource_record.attributes = params[resource_param_key].present? ? resource_params : {}
|
32
|
+
maybe_apply_submitted_resource_params!
|
34
33
|
@form = build_form
|
35
34
|
|
36
35
|
render :new
|
37
36
|
end
|
38
37
|
|
39
|
-
# GET /resources/1/edit
|
40
|
-
def edit
|
41
|
-
authorize resource_record
|
42
|
-
|
43
|
-
# set params if they have been passed
|
44
|
-
resource_record.attributes = params[resource_param_key].present? ? resource_params : {}
|
45
|
-
@form = build_form
|
46
|
-
|
47
|
-
render :edit
|
48
|
-
end
|
49
|
-
|
50
38
|
# POST /resources(.{format})
|
51
39
|
def create
|
52
40
|
authorize resource_class
|
@@ -73,6 +61,16 @@ module Plutonium
|
|
73
61
|
end
|
74
62
|
end
|
75
63
|
|
64
|
+
# GET /resources/1/edit
|
65
|
+
def edit
|
66
|
+
authorize resource_record
|
67
|
+
|
68
|
+
maybe_apply_submitted_resource_params!
|
69
|
+
@form = build_form
|
70
|
+
|
71
|
+
render :edit
|
72
|
+
end
|
73
|
+
|
76
74
|
# PATCH/PUT /resources/1(.{format})
|
77
75
|
def update
|
78
76
|
authorize resource_record
|
@@ -10,12 +10,12 @@ module Plutonium
|
|
10
10
|
|
11
11
|
private
|
12
12
|
|
13
|
-
def resource_presenter(resource_class)
|
13
|
+
def resource_presenter(resource_class, resource_record)
|
14
14
|
raise NotImplementedError, "#{self.class}#resource_presenter"
|
15
15
|
end
|
16
16
|
|
17
17
|
def current_presenter
|
18
|
-
resource_presenter resource_class
|
18
|
+
resource_presenter resource_class, @resource_record
|
19
19
|
end
|
20
20
|
|
21
21
|
def presentable_attributes
|
@@ -34,7 +34,8 @@ module Plutonium
|
|
34
34
|
fields: current_presenter.defined_renderers_for(presentable_attributes),
|
35
35
|
actions: current_presenter.actions,
|
36
36
|
pagination: @pagy,
|
37
|
-
search_object: @ransack
|
37
|
+
search_object: @ransack,
|
38
|
+
search_field: current_presenter.search_field
|
38
39
|
)
|
39
40
|
end
|
40
41
|
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Plutonium
|
2
|
+
module Core
|
3
|
+
module Fields
|
4
|
+
module Inputs
|
5
|
+
class AttachmentInput < SimpleFormInput
|
6
|
+
attr_reader :reflection
|
7
|
+
|
8
|
+
def initialize(name, reflection:, **user_options)
|
9
|
+
@reflection = reflection
|
10
|
+
super(name, **user_options)
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def input_options
|
16
|
+
options = {attachment: true} # enable the attachment component
|
17
|
+
options[:input_html] = {multiple: true} if reflection.macro == :has_many_attached
|
18
|
+
options
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -2,7 +2,7 @@ module Plutonium
|
|
2
2
|
module Core
|
3
3
|
module Fields
|
4
4
|
module Inputs
|
5
|
-
class
|
5
|
+
class Base
|
6
6
|
attr_reader :name, :user_options
|
7
7
|
|
8
8
|
def initialize(name, **user_options)
|
@@ -10,7 +10,9 @@ module Plutonium
|
|
10
10
|
@user_options = user_options
|
11
11
|
end
|
12
12
|
|
13
|
-
def render(f, record)
|
13
|
+
def render(f, record)
|
14
|
+
raise NotImplementedError, "#{self.class}#render"
|
15
|
+
end
|
14
16
|
|
15
17
|
def collect(params)
|
16
18
|
# Handles multi parameter attributes
|
@@ -8,40 +8,22 @@ module Plutonium
|
|
8
8
|
extend ::SimpleForm::MapType
|
9
9
|
|
10
10
|
map_type :has_one, to: Plutonium::Core::Fields::Inputs::NoopInput
|
11
|
-
map_type :belongs_to, to: Plutonium::Core::Fields::Inputs::
|
12
|
-
map_type :has_many, to: Plutonium::Core::Fields::Inputs::
|
11
|
+
map_type :belongs_to, to: Plutonium::Core::Fields::Inputs::BelongsToAssociationInput
|
12
|
+
map_type :has_many, to: Plutonium::Core::Fields::Inputs::HasManyAssociationInput
|
13
|
+
map_type :attachment, to: Plutonium::Core::Fields::Inputs::AttachmentInput
|
13
14
|
|
14
15
|
def self.build(name, type:, **)
|
15
|
-
mapping = mappings[type] || Plutonium::Core::Fields::Inputs::
|
16
|
+
mapping = mappings[type] || Plutonium::Core::Fields::Inputs::SimpleFormInput
|
16
17
|
mapping.new(name, **)
|
17
|
-
|
18
|
-
# type ||= :slim_select if options.key? :collection
|
19
|
-
|
20
|
-
# case type
|
21
|
-
# when :belongs_to
|
22
|
-
# Plutonium::Core::Fields::Inputs::BelongsToInput.new(name, **)
|
23
|
-
# when :has_one
|
24
|
-
# Plutonium::Core::Fields::Inputs::NoopInput.new
|
25
|
-
# when :has_many
|
26
|
-
# Plutonium::Core::Fields::Inputs::HasManyInput.new(name, **)
|
27
|
-
# else
|
28
|
-
# Plutonium::Core::Fields::Inputs::BasicInput.new(name, **)
|
29
|
-
# end
|
30
18
|
end
|
31
19
|
|
32
20
|
def self.for_resource_attribute(resource_class, attr_name, **options)
|
33
21
|
type = nil
|
34
22
|
|
35
|
-
if resource_class.
|
36
|
-
attachment = resource_class.reflect_on_association(:"#{attr_name}_attachment") || \
|
37
|
-
resource_class.reflect_on_association(:"#{attr_name}_attachments")
|
38
|
-
association = resource_class.reflect_on_association(attr_name)
|
39
|
-
end
|
40
|
-
|
41
|
-
if attachment.present?
|
23
|
+
if (attachment = resource_class.try(:reflect_on_attachment, attr_name))
|
42
24
|
type = :attachment
|
43
|
-
options[:
|
44
|
-
elsif association.
|
25
|
+
options[:reflection] = attachment
|
26
|
+
elsif (association = resource_class.try(:reflect_on_association, attr_name))
|
45
27
|
type = association.macro
|
46
28
|
options[:reflection] = association
|
47
29
|
elsif (column = resource_class.try(:column_for_attribute, attr_name))
|
@@ -5,12 +5,14 @@ module Plutonium
|
|
5
5
|
extend ActiveSupport::Autoload
|
6
6
|
|
7
7
|
eager_autoload do
|
8
|
+
autoload :AttachmentInput
|
9
|
+
autoload :Base
|
10
|
+
autoload :BelongsToAssociationInput
|
8
11
|
autoload :Factory
|
9
|
-
autoload :
|
10
|
-
autoload :BasicInput
|
11
|
-
autoload :BelongsToInput
|
12
|
-
autoload :HasManyInput
|
12
|
+
autoload :HasManyAssociationInput
|
13
13
|
autoload :NoopInput
|
14
|
+
autoload :SimpleFormAssociationInput
|
15
|
+
autoload :SimpleFormInput
|
14
16
|
end
|
15
17
|
end
|
16
18
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Plutonium
|
2
|
+
module Core
|
3
|
+
module Fields
|
4
|
+
module Renderers
|
5
|
+
class AttachmentRenderer < BasicRenderer
|
6
|
+
attr_reader :reflection
|
7
|
+
|
8
|
+
def initialize(name, reflection:, **user_options)
|
9
|
+
@reflection = reflection
|
10
|
+
super(name, **user_options)
|
11
|
+
end
|
12
|
+
|
13
|
+
def render(view_context, record)
|
14
|
+
view_context.attachment_preview record.send(name), **options
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def renderer_options
|
20
|
+
{
|
21
|
+
caption: true
|
22
|
+
}
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -8,35 +8,21 @@ module Plutonium
|
|
8
8
|
extend ::SimpleForm::MapType
|
9
9
|
|
10
10
|
map_type :belongs_to, :has_one, :has_many, to: Plutonium::Core::Fields::Renderers::AssociationRenderer
|
11
|
+
map_type :attachment, to: Plutonium::Core::Fields::Renderers::AttachmentRenderer
|
11
12
|
|
12
13
|
def self.build(name, type:, **)
|
13
14
|
mapping = mappings[type] || Plutonium::Core::Fields::Renderers::BasicRenderer
|
14
15
|
mapping.new(name, **)
|
15
|
-
|
16
|
-
# type ||= :slim_select if options.key? :collection
|
17
|
-
|
18
|
-
# case type
|
19
|
-
# when :belongs_to, :has_one, :has_many
|
20
|
-
# Plutonium::Core::Fields::Renderers::AssociationRenderer.new(name, **)
|
21
|
-
# else
|
22
|
-
# Plutonium::Core::Fields::Renderers::BasicRenderer.new(name, **)
|
23
|
-
# end
|
24
16
|
end
|
25
17
|
|
26
18
|
def self.for_resource_attribute(resource_class, attr_name, **options)
|
27
19
|
type = nil
|
28
20
|
options[:label] ||= resource_class.human_attribute_name(attr_name)
|
29
21
|
|
30
|
-
if resource_class.
|
31
|
-
attachment = resource_class.reflect_on_association(:"#{attr_name}_attachment") || \
|
32
|
-
resource_class.reflect_on_association(:"#{attr_name}_attachments")
|
33
|
-
association = resource_class.reflect_on_association(attr_name)
|
34
|
-
end
|
35
|
-
|
36
|
-
if attachment.present?
|
22
|
+
if (attachment = resource_class.try(:reflect_on_attachment, attr_name))
|
37
23
|
type = :attachment
|
38
|
-
options[:
|
39
|
-
elsif association.
|
24
|
+
options[:reflection] = attachment
|
25
|
+
elsif (association = resource_class.try(:reflect_on_association, attr_name))
|
40
26
|
type = association.macro
|
41
27
|
options[:reflection] = association
|
42
28
|
elsif (column = resource_class.try(:column_for_attribute, attr_name))
|
@@ -1,10 +1,10 @@
|
|
1
1
|
module Plutonium
|
2
2
|
module Core
|
3
3
|
module UI
|
4
|
-
Collection = Data.define :resource_class, :records, :fields, :actions, :pagination, :search_object do
|
4
|
+
Collection = Data.define :resource_class, :records, :fields, :actions, :pagination, :search_object, :search_field do
|
5
5
|
def initialize(
|
6
6
|
resource_class:, records: [], fields: {}, actions: Plutonium::Core::Actions::Collection.new,
|
7
|
-
pagination: nil, search_object: nil
|
7
|
+
pagination: nil, search_object: nil, search_field: nil
|
8
8
|
)
|
9
9
|
super
|
10
10
|
end
|
@@ -6,23 +6,23 @@ module Plutonium
|
|
6
6
|
tag.div class: [options[:identity_class], "attachment-preview-container d-flex flex-wrap gap-1 my-1"],
|
7
7
|
data: {controller: "attachment-preview-container"} do
|
8
8
|
Array(attachments).each do |attachment|
|
9
|
-
next unless attachment.
|
9
|
+
next unless attachment.url.present?
|
10
10
|
|
11
11
|
concat begin
|
12
12
|
tag.div class: [options[:identity_class], "attachment-preview d-inline-block text-center"],
|
13
|
-
title: attachment.
|
13
|
+
title: attachment.filename,
|
14
14
|
data: {
|
15
15
|
controller: "attachment-preview",
|
16
|
-
attachment_preview_mime_type_value: attachment.
|
17
|
-
attachment_preview_thumbnail_url_value: attachment
|
16
|
+
attachment_preview_mime_type_value: attachment.content_type,
|
17
|
+
attachment_preview_thumbnail_url_value: _attachment_thumbnail_url(attachment)
|
18
18
|
} do
|
19
19
|
tag.figure class: "figure my-1", style: "width: 160px;" do
|
20
20
|
concat attachment_preview_thumnail(attachment)
|
21
21
|
concat begin
|
22
22
|
tag.figcaption class: "figure-caption text-truncate" do
|
23
23
|
if options[:caption]
|
24
|
-
caption = options[:caption].is_a?(String) ? options[:caption] : attachment.
|
25
|
-
concat link_to(caption, attachment.
|
24
|
+
caption = options[:caption].is_a?(String) ? options[:caption] : attachment.filename
|
25
|
+
concat link_to(caption, attachment.url, class: "text-decoration-none", target: :blank)
|
26
26
|
end
|
27
27
|
|
28
28
|
if block_given?
|
@@ -40,23 +40,34 @@ module Plutonium
|
|
40
40
|
end
|
41
41
|
|
42
42
|
def attachment_preview_thumnail(attachment)
|
43
|
-
return unless attachment.
|
43
|
+
return unless attachment.url.present?
|
44
44
|
|
45
45
|
# Any changes made here must be reflected in attachment_input_controller#buildPreviewTemplate
|
46
46
|
|
47
47
|
tag.div class: "d-inline-block img-thumbnail", data: {attachment_preview_target: "thumbnail"} do
|
48
|
-
|
49
|
-
|
48
|
+
thumbnail_url = _attachment_thumbnail_url(attachment)
|
49
|
+
link_body = if thumbnail_url
|
50
|
+
image_tag thumbnail_url, style: "width:100%; height:100%; object-fit: contain;"
|
50
51
|
else
|
51
|
-
attachment
|
52
|
+
_attachment_extension(attachment)
|
52
53
|
end
|
53
54
|
|
54
|
-
link_to link_body, attachment.
|
55
|
+
link_to link_body, attachment.url, style: "width:150px; height:150px; line-height: 150px;",
|
55
56
|
class: "d-block text-decoration-none user-select-none fs-5 font-monospace text-body-secondary",
|
56
57
|
target: :blank,
|
57
58
|
data: {attachment_preview_target: "thumbnailLink"}
|
58
59
|
end
|
59
60
|
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def _attachment_thumbnail_url(attachment)
|
65
|
+
attachment.url if attachment.representable?
|
66
|
+
end
|
67
|
+
|
68
|
+
def _attachment_extension(attachment)
|
69
|
+
attachment.try(:extension) || File.extname(attachment.filename.to_s)
|
70
|
+
end
|
60
71
|
end
|
61
72
|
end
|
62
73
|
end
|
@@ -3,10 +3,6 @@ module Plutonium
|
|
3
3
|
module FormHelper
|
4
4
|
include ActionView::Helpers::FormHelper
|
5
5
|
|
6
|
-
#
|
7
|
-
# Override the original form_for helper to disable turbo forms by default if not
|
8
|
-
# explicitly opted into
|
9
|
-
#
|
10
6
|
def resource_form_for(record, options = {}, &block)
|
11
7
|
turbo_frame = options.key?(:turbo_frame) ? options[:turbo_frame] : "_top"
|
12
8
|
options = {
|
@@ -17,6 +13,8 @@ module Plutonium
|
|
17
13
|
}
|
18
14
|
}.deep_merge! options
|
19
15
|
|
16
|
+
# record = adapt_route_args(record) unless record.is_a?(Array) || options.key?(:url)
|
17
|
+
|
20
18
|
simple_form_for(record, options, &block)
|
21
19
|
end
|
22
20
|
end
|
@@ -6,11 +6,11 @@ module Plutonium
|
|
6
6
|
include Plutonium::Policy::Initializer
|
7
7
|
|
8
8
|
def resolve
|
9
|
-
scope = context.resource_class.all
|
10
|
-
if @context.parent.present?
|
11
|
-
scope = scope.associated_with(@context.parent)
|
12
|
-
elsif @context.scope.present?
|
13
|
-
scope = scope.associated_with(@context.scope)
|
9
|
+
scope = context.resource_context.resource_class.all
|
10
|
+
if @context.resource_context.parent.present?
|
11
|
+
scope = scope.associated_with(@context.resource_context.parent)
|
12
|
+
elsif @context.resource_context.scope.present?
|
13
|
+
scope = scope.associated_with(@context.resource_context.scope)
|
14
14
|
end
|
15
15
|
scope
|
16
16
|
end
|
@@ -1,15 +1,5 @@
|
|
1
1
|
module Plutonium
|
2
2
|
module Reactor
|
3
|
-
|
4
|
-
attr_reader :user, :resource_record, :resource_class, :parent, :scope
|
5
|
-
|
6
|
-
def initialize(user:, resource_record:, resource_class:, parent: nil, scope: nil)
|
7
|
-
@user = user
|
8
|
-
@resource_record = resource_record
|
9
|
-
@resource_class = resource_class || resource_record&.class
|
10
|
-
@parent = parent
|
11
|
-
@scope = scope
|
12
|
-
end
|
13
|
-
end
|
3
|
+
ResourceContext = Data.define :resource_class, :parent, :scope
|
14
4
|
end
|
15
5
|
end
|
@@ -36,6 +36,12 @@ module Plutonium
|
|
36
36
|
before_action :set_page_title
|
37
37
|
before_action :set_sidebar_menu
|
38
38
|
|
39
|
+
before_action do
|
40
|
+
return unless defined?(ActiveStorage)
|
41
|
+
|
42
|
+
ActiveStorage::Current.url_options = {protocol: request.protocol, host: request.host, port: request.port}
|
43
|
+
end
|
44
|
+
|
39
45
|
# https://github.com/ddnexus/pagy/blob/master/docs/extras/headers.md#headers
|
40
46
|
after_action { pagy_headers_merge(@pagy) if @pagy }
|
41
47
|
|
@@ -52,10 +58,15 @@ module Plutonium
|
|
52
58
|
end
|
53
59
|
helper_method :resource_record
|
54
60
|
|
61
|
+
def submitted_resource_params
|
62
|
+
@submitted_resource_params ||= begin
|
63
|
+
strong_parameters = resource_class.strong_parameters_for(*permitted_attributes)
|
64
|
+
params.require(resource_param_key).permit(*strong_parameters).nilify.to_h
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
55
68
|
def resource_params
|
56
|
-
|
57
|
-
# NOTE: Brakeman warning ignored for MassAssignment because inputs are filtered manually
|
58
|
-
input_params = params.require(resource_param_key).permit!.nilify.to_h
|
69
|
+
input_params = submitted_resource_params.dup
|
59
70
|
|
60
71
|
# Override any entity scoping params
|
61
72
|
input_params[scoped_entity_param_key] = current_scoped_entity if scoped_to_entity?
|
@@ -64,6 +75,7 @@ module Plutonium
|
|
64
75
|
input_params[parent_input_param] = current_parent if current_parent.present?
|
65
76
|
input_params[:"#{parent_input_param}_id"] = current_parent.id if current_parent.present?
|
66
77
|
|
78
|
+
# additionally filter our input_params through our inputs
|
67
79
|
current_presenter.defined_inputs_for(permitted_attributes)
|
68
80
|
.values.map { |input| input.collect input_params }
|
69
81
|
.reduce(:merge)
|
@@ -74,6 +86,19 @@ module Plutonium
|
|
74
86
|
end
|
75
87
|
helper_method :resource_param_key
|
76
88
|
|
89
|
+
# sets params on submitted_resource_params if they have been passed
|
90
|
+
def maybe_apply_submitted_resource_params!
|
91
|
+
# this is useful in dynamic forms as we can read the resource record to determine how to define our inputs
|
92
|
+
# we need to ensure that this is being called from get because
|
93
|
+
# it is potentially unsafe since we don't apply the input filter. see #resource_params
|
94
|
+
# would have been nice to be able to, but we can't until we have the presenter, and the presenter
|
95
|
+
# requires the resource_record for our dynamic forms
|
96
|
+
# is this perfect? no. but it works.
|
97
|
+
raise "🚨🚨🚨 this should be called from actions that are not persisting this data" unless request.method == "GET"
|
98
|
+
|
99
|
+
resource_record.attributes = submitted_resource_params if params[resource_param_key].present?
|
100
|
+
end
|
101
|
+
|
77
102
|
# Layout
|
78
103
|
|
79
104
|
def set_page_title
|
@@ -90,9 +115,7 @@ module Plutonium
|
|
90
115
|
|
91
116
|
def resource_context
|
92
117
|
Plutonium::Reactor::ResourceContext.new(
|
93
|
-
user: current_user,
|
94
118
|
resource_class:,
|
95
|
-
resource_record: @resource_record,
|
96
119
|
parent: current_parent,
|
97
120
|
scope: scoped_to_entity? ? current_scoped_entity : nil
|
98
121
|
)
|
@@ -83,7 +83,7 @@ module Plutonium
|
|
83
83
|
def autodetect_fields_for(method_name)
|
84
84
|
maybe_warn_autodetect_usage method_name
|
85
85
|
|
86
|
-
context.resource_class.resource_field_names
|
86
|
+
context.resource_context.resource_class.resource_field_names
|
87
87
|
end
|
88
88
|
|
89
89
|
def maybe_warn_autodetect_usage(method)
|
@@ -95,7 +95,7 @@ module Plutonium
|
|
95
95
|
Resource field auto-detection: #{self.class}##{method}
|
96
96
|
|
97
97
|
Auto-detected resource fields result in security holes and will fail outside of development.
|
98
|
-
Override #{context.resource_class}Policy or #{self.class} with your own ##{method} method.
|
98
|
+
Override #{context.resource_context.resource_class}Policy or #{self.class} with your own ##{method} method.
|
99
99
|
|
100
100
|
🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨
|
101
101
|
)
|
@@ -4,17 +4,22 @@ module Plutonium
|
|
4
4
|
include Plutonium::Core::Definers::FieldDefiner
|
5
5
|
include Plutonium::Core::Definers::ActionDefiner
|
6
6
|
|
7
|
-
def initialize(context)
|
7
|
+
def initialize(context, resource_record)
|
8
8
|
@context = context
|
9
|
+
@resource_record = resource_record
|
9
10
|
|
10
11
|
define_standard_actions
|
11
12
|
define_actions
|
12
13
|
define_fields
|
13
14
|
end
|
14
15
|
|
16
|
+
def search_field
|
17
|
+
nil
|
18
|
+
end
|
19
|
+
|
15
20
|
private
|
16
21
|
|
17
|
-
attr_reader :context
|
22
|
+
attr_reader :context, :resource_record
|
18
23
|
|
19
24
|
def define_fields
|
20
25
|
# override this in child presenters for custom field definitions
|
@@ -10,21 +10,23 @@ module Plutonium
|
|
10
10
|
named_scope = :"associated_with_#{record.model_name.singular}"
|
11
11
|
return send(named_scope, record) if respond_to?(named_scope)
|
12
12
|
|
13
|
+
# TOD: add suppport for polymorphic associations
|
14
|
+
|
13
15
|
# TODO: add logging
|
14
16
|
if (own_association = reflect_on_all_associations.find { |assoc| assoc.klass == record.class })
|
15
17
|
case own_association.macro
|
16
18
|
when :has_one
|
17
19
|
joins(own_association.name).where({
|
18
|
-
own_association.name
|
20
|
+
own_association.name => {
|
19
21
|
record.class.primary_key => record.id
|
20
22
|
}
|
21
23
|
})
|
22
24
|
when :belongs_to
|
23
25
|
where(own_association.name => record)
|
24
26
|
when :has_many
|
25
|
-
joins(own_association.name).where(own_association.klass.table_name
|
27
|
+
joins(own_association.name).where(own_association.klass.table_name => record)
|
26
28
|
else
|
27
|
-
raise
|
29
|
+
raise NotImplementedError, "associated_with->##{own_association.macro}"
|
28
30
|
end
|
29
31
|
elsif (record_association = record.class.reflect_on_all_associations.find { |assoc| assoc.klass == klass })
|
30
32
|
# TODO: add a warning here about a potentially poor performing query
|
@@ -33,37 +35,66 @@ module Plutonium
|
|
33
35
|
raise "Could not resolve the association between '#{klass.name}' and '#{record.class.name}'\n\n" \
|
34
36
|
"Define\n" \
|
35
37
|
" 1. the associations between the models\n" \
|
36
|
-
" 2. a named scope e.g.\n\n" \
|
38
|
+
" 2. a named scope on #{klass.name} e.g.\n\n" \
|
37
39
|
"scope :#{named_scope}, ->(#{record.model_name.singular}) { do_something_here }"
|
38
40
|
end
|
39
41
|
end
|
40
42
|
end
|
41
43
|
|
42
44
|
module ClassMethods
|
43
|
-
|
45
|
+
def resource_field_names
|
46
|
+
@resource_field_names ||= belongs_to_association_field_names +
|
47
|
+
has_one_attached_field_names + has_one_association_field_names +
|
48
|
+
has_many_attached_field_names + has_many_association_field_names +
|
49
|
+
content_column_field_names
|
50
|
+
end
|
44
51
|
|
45
|
-
def
|
46
|
-
|
52
|
+
def belongs_to_association_field_names
|
53
|
+
@belongs_to_association_field_names ||= reflect_on_all_associations(:belongs_to).map(&:name)
|
54
|
+
end
|
47
55
|
|
48
|
-
|
56
|
+
def has_one_association_field_names
|
57
|
+
@has_one_association_field_names ||= reflect_on_all_associations(:has_one)
|
58
|
+
.map { |assoc| /_attachment$|_blob$/.match?(assoc.name) ? nil : assoc.name }
|
59
|
+
.compact
|
60
|
+
end
|
49
61
|
|
50
|
-
|
51
|
-
|
62
|
+
def has_many_association_field_names
|
63
|
+
@has_many_association_field_names ||= reflect_on_all_associations(:has_many)
|
64
|
+
.map { |assoc| /_attachments$|_blobs$/.match?(assoc.name) ? nil : assoc.name }
|
65
|
+
.compact
|
66
|
+
end
|
52
67
|
|
53
|
-
|
54
|
-
|
68
|
+
def has_one_attached_field_names
|
69
|
+
@has_one_attached_field_names ||= reflect_on_all_attachments
|
70
|
+
.map { |a| (a.macro == :has_one_attached) ? a.name : nil }
|
71
|
+
.compact
|
55
72
|
end
|
56
73
|
|
57
|
-
def
|
58
|
-
|
74
|
+
def has_many_attached_field_names
|
75
|
+
@has_many_attached_field_names ||= reflect_on_all_attachments
|
76
|
+
.map { |a| (a.macro == :has_many_attached) ? a.name : nil }
|
77
|
+
.compact
|
78
|
+
end
|
59
79
|
|
60
|
-
|
80
|
+
def content_column_field_names
|
81
|
+
@content_column_field_names ||= content_columns.map { |col| col.name.to_sym }
|
82
|
+
end
|
61
83
|
|
62
|
-
|
63
|
-
|
84
|
+
def has_many_association_routes
|
85
|
+
@has_many_association_routes ||= reflect_on_all_associations(:has_many).map { |assoc| assoc.klass.model_name.plural }
|
86
|
+
end
|
64
87
|
|
65
|
-
|
66
|
-
|
88
|
+
#
|
89
|
+
# Returns the strong parameters definition for the given attribute names
|
90
|
+
#
|
91
|
+
# @param [Array] *attributes Attribute names
|
92
|
+
#
|
93
|
+
# @return [Array] A strong parameters compatible array e.g.
|
94
|
+
# [:title, :body, {:images=>[]}, {:docs=>[]}]
|
95
|
+
#
|
96
|
+
def strong_parameters_for(*attributes)
|
97
|
+
strong_parameters_definition.slice(*attributes).map { |key, value| value.nil? ? key : {key => value} }
|
67
98
|
end
|
68
99
|
|
69
100
|
# Ransack
|
@@ -84,29 +115,60 @@ module Plutonium
|
|
84
115
|
[]
|
85
116
|
end
|
86
117
|
|
87
|
-
|
88
|
-
@resource_field_names ||= belongs_to_association_field_names + has_one_association_field_names +
|
89
|
-
has_many_association_field_names + content_column_field_names
|
90
|
-
end
|
118
|
+
private
|
91
119
|
|
92
|
-
def
|
93
|
-
@
|
94
|
-
|
120
|
+
def strong_parameters_definition
|
121
|
+
# @strong_parameters ||= begin
|
122
|
+
@strong_parameters = begin
|
123
|
+
content_column_parameters = content_column_field_names.map do |name|
|
124
|
+
column = columns_hash[name.to_s]
|
95
125
|
|
96
|
-
|
97
|
-
|
98
|
-
|
126
|
+
type = nil
|
127
|
+
type = [] if column&.try(:array?)
|
128
|
+
type = {} if [:json, :jsonb].include?(column&.type)
|
99
129
|
|
100
|
-
|
101
|
-
|
130
|
+
[name, type]
|
131
|
+
end
|
132
|
+
parameters = content_column_parameters.to_h
|
133
|
+
|
134
|
+
# TODO: add nested support
|
135
|
+
|
136
|
+
parameters.merge! belongs_to_association_field_names.map { |name| [name, nil] }.to_h
|
137
|
+
parameters.merge! has_one_association_field_names.map { |name| [name, nil] }.to_h
|
138
|
+
parameters.merge! has_one_attached_field_names.map { |name| [name, nil] }.to_h
|
139
|
+
|
140
|
+
parameters.merge! has_many_association_field_names.map { |name| [name, []] }.to_h
|
141
|
+
parameters.merge! has_many_attached_field_names.map { |name| [name, []] }.to_h
|
142
|
+
|
143
|
+
# e.g. {:title=>nil, :body=>nil, :state=>nil, :created_at=>nil, :updated_at=>nil, :image=>nil, :images=>[]}
|
144
|
+
parameters
|
145
|
+
end
|
102
146
|
end
|
103
147
|
|
104
|
-
|
105
|
-
|
148
|
+
# Path parameters
|
149
|
+
|
150
|
+
def path_parameter(param_name)
|
151
|
+
param_name = param_name.to_sym
|
152
|
+
|
153
|
+
scope :from_path_param, ->(param) { where(param_name => param) }
|
154
|
+
|
155
|
+
define_method :to_param do
|
156
|
+
return nil unless persisted?
|
157
|
+
|
158
|
+
send param_name
|
159
|
+
end
|
106
160
|
end
|
107
161
|
|
108
|
-
def
|
109
|
-
|
162
|
+
def dynamic_path_parameter(param_name)
|
163
|
+
param_name = param_name.to_sym
|
164
|
+
|
165
|
+
scope :from_path_param, ->(param) { where(id: param.split("-").first) }
|
166
|
+
|
167
|
+
define_method :to_param do
|
168
|
+
return nil unless persisted?
|
169
|
+
|
170
|
+
"#{id}-#{send(param_name)}".parameterize
|
171
|
+
end
|
110
172
|
end
|
111
173
|
end
|
112
174
|
|
data/lib/plutonium/reactor.rb
CHANGED
@@ -14,7 +14,7 @@ module Plutonium
|
|
14
14
|
next if value.nil?
|
15
15
|
|
16
16
|
template.concat begin
|
17
|
-
template.display_attachment_value value, identity_class: input_class, caption:
|
17
|
+
template.display_attachment_value value, identity_class: input_class, caption: caption? do |attachment|
|
18
18
|
[
|
19
19
|
# These hidden fields allow us to preserve the already uploaded files.
|
20
20
|
# For has_one_attached, it overrides the hidden field previously added
|
@@ -25,7 +25,8 @@ module Plutonium
|
|
25
25
|
@builder.hidden_field(attribute_name, multiple: multiple?, value: attachment.signed_id),
|
26
26
|
|
27
27
|
# By removing this component, the hidden field is gone, which allows us to remove the files from active storage
|
28
|
-
template.content_tag(:p, class: "text-danger m-0", role: :button,
|
28
|
+
template.content_tag(:p, class: "text-danger m-0", role: :button,
|
29
|
+
data: {action: "click->attachment-preview#remove"}) do
|
29
30
|
template.content_tag :span, " Delete", class: "bi bi-trash"
|
30
31
|
end
|
31
32
|
]
|
@@ -41,7 +42,11 @@ module Plutonium
|
|
41
42
|
end
|
42
43
|
|
43
44
|
def multiple?
|
44
|
-
options[:multiple]
|
45
|
+
options[:input_html] && options[:input_html][:multiple]
|
46
|
+
end
|
47
|
+
|
48
|
+
def caption?
|
49
|
+
options.key?(:caption) ? options[:caption] : true
|
45
50
|
end
|
46
51
|
|
47
52
|
def maybe_setup_direct_uploads
|
@@ -74,4 +79,5 @@ module Plutonium
|
|
74
79
|
end
|
75
80
|
end
|
76
81
|
end
|
82
|
+
# Register with simple_form
|
77
83
|
SimpleForm.include_component(Plutonium::SimpleForm::AttachmentComponent)
|
data/lib/plutonium/version.rb
CHANGED
data/lib/plutonium.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: plutonium
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stefan Froelich
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-02-
|
11
|
+
date: 2024-02-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -428,14 +428,17 @@ files:
|
|
428
428
|
- lib/plutonium/core/definers/renderer_definer.rb
|
429
429
|
- lib/plutonium/core/fields.rb
|
430
430
|
- lib/plutonium/core/fields/inputs.rb
|
431
|
-
- lib/plutonium/core/fields/inputs/
|
432
|
-
- lib/plutonium/core/fields/inputs/
|
433
|
-
- lib/plutonium/core/fields/inputs/
|
431
|
+
- lib/plutonium/core/fields/inputs/attachment_input.rb
|
432
|
+
- lib/plutonium/core/fields/inputs/base.rb
|
433
|
+
- lib/plutonium/core/fields/inputs/belongs_to_association_input.rb
|
434
434
|
- lib/plutonium/core/fields/inputs/factory.rb
|
435
|
-
- lib/plutonium/core/fields/inputs/
|
435
|
+
- lib/plutonium/core/fields/inputs/has_many_association_input.rb
|
436
436
|
- lib/plutonium/core/fields/inputs/noop_input.rb
|
437
|
+
- lib/plutonium/core/fields/inputs/simple_form_association_input.rb
|
438
|
+
- lib/plutonium/core/fields/inputs/simple_form_input.rb
|
437
439
|
- lib/plutonium/core/fields/renderers.rb
|
438
440
|
- lib/plutonium/core/fields/renderers/association_renderer.rb
|
441
|
+
- lib/plutonium/core/fields/renderers/attachment_renderer.rb
|
439
442
|
- lib/plutonium/core/fields/renderers/basic_renderer.rb
|
440
443
|
- lib/plutonium/core/fields/renderers/factory.rb
|
441
444
|
- lib/plutonium/core/ui.rb
|
@@ -469,8 +472,10 @@ files:
|
|
469
472
|
- lib/plutonium/policy/scope.rb
|
470
473
|
- lib/plutonium/preserved__/field.rb
|
471
474
|
- lib/plutonium/preserved__/input.rb
|
475
|
+
- lib/plutonium/railtie.rb
|
472
476
|
- lib/plutonium/reactor.rb
|
473
477
|
- lib/plutonium/reactor/core.rb
|
478
|
+
- lib/plutonium/reactor/policy_context.rb
|
474
479
|
- lib/plutonium/reactor/resource_context.rb
|
475
480
|
- lib/plutonium/reactor/resource_controller.rb
|
476
481
|
- lib/plutonium/reactor/resource_interaction.rb
|