plutonium 0.8.0 → 0.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +7 -0
  3. data/Rakefile +10 -0
  4. data/app/assets/build/plutonium.js +5122 -0
  5. data/app/assets/javascripts/controllers/index.js +34 -0
  6. data/app/assets/javascripts/controllers/resource_dismiss_controller.js +37 -0
  7. data/app/assets/javascripts/controllers/resource_drop_down_controller.js +29 -0
  8. data/app/assets/javascripts/plutonium-app.js +7 -0
  9. data/app/assets/javascripts/plutonium.js +1 -0
  10. data/app/assets/{js → javascripts}/turbo/index.js +1 -1
  11. data/app/views/application/_flash.html.erb +1 -1
  12. data/app/views/application/_flash_alerts.html.erb +51 -7
  13. data/app/views/application/_flash_toasts.html.erb +53 -23
  14. data/app/views/application/_resource_header.html.erb +563 -561
  15. data/app/views/components/form/form_builder.rb +2 -2
  16. data/app/views/components/form/form_component.html.erb +5 -6
  17. data/app/views/components/interactive_action_form/interactive_action_form_component.html.erb +1 -1
  18. data/app/views/components/nested_resource_form_fields/nested_resource_form_fields_component.html.erb +66 -0
  19. data/app/views/components/nested_resource_form_fields/nested_resource_form_fields_component.rb +23 -0
  20. data/app/views/components/nested_resource_form_fields/nested_resource_form_fields_controller.js +64 -0
  21. data/app/views/components/sidebar/sidebar_component.html.erb +61 -63
  22. data/app/views/components/table_search_input/table_search_input_component.html.erb +1 -1
  23. data/app/views/layouts/resource.html copy.erb +0 -2
  24. data/app/views/layouts/resource.html.erb +1 -3
  25. data/app/views/layouts/rodauth.html.erb +0 -1
  26. data/app/views/resource/_interactive_resource_action_form.html.erb +1 -1
  27. data/css.manifest +3 -0
  28. data/esbuild.config.js +44 -0
  29. data/exe/pug +6 -0
  30. data/lib/generators/pu/gen/component/component_generator.rb +14 -5
  31. data/lib/generators/pu/gen/pug/pug_generator.rb +1 -1
  32. data/lib/generators/pu/lib/plutonium_generators/cli.rb +42 -0
  33. data/lib/generators/pu/lib/plutonium_generators/concerns/actions.rb +86 -72
  34. data/lib/generators/pu/lib/plutonium_generators/generator.rb +1 -5
  35. data/lib/generators/pu/lib/plutonium_generators.rb +8 -0
  36. data/lib/generators/pu/rodauth/install_generator.rb +1 -2
  37. data/lib/plutonium/core/actions/collection.rb +1 -1
  38. data/lib/plutonium/core/controllers/authorizable.rb +4 -4
  39. data/lib/plutonium/core/fields/inputs/base.rb +1 -1
  40. data/lib/plutonium/core/fields/inputs/nested_input.rb +57 -0
  41. data/lib/plutonium/core/fields/inputs/noop_input.rb +1 -1
  42. data/lib/plutonium/core/fields/inputs/phone_input.rb +1 -1
  43. data/lib/plutonium/core/fields/inputs/polymorphic_belongs_to_association_input.rb +1 -1
  44. data/lib/plutonium/core/fields/inputs/simple_form_association_input.rb +1 -1
  45. data/lib/plutonium/core/fields/inputs/simple_form_input.rb +1 -1
  46. data/lib/plutonium/pkg/base.rb +0 -4
  47. data/lib/plutonium/railtie.rb +10 -2
  48. data/lib/plutonium/resource/policy.rb +6 -0
  49. data/lib/plutonium/resource/presenter.rb +35 -0
  50. data/lib/plutonium/resource/record.rb +40 -7
  51. data/lib/plutonium/version.rb +1 -1
  52. data/lib/plutonium.rb +17 -14
  53. data/package.json +4 -3
  54. data/postcss.config.js +1 -1
  55. data/public/plutonium-assets/plutonium-app-36KN5FVJ.js +6 -0
  56. data/public/plutonium-assets/plutonium-app-36KN5FVJ.js.map +7 -0
  57. data/public/plutonium-assets/plutonium.50232e35b5495f5ad90d.css +3415 -0
  58. data/tailwind.config.js +11 -12
  59. data/templates/base.rb +8 -0
  60. metadata +28 -21
  61. data/app/assets/js/controllers/application.js +0 -6
  62. data/app/assets/js/controllers/dropdown_controller.js +0 -12
  63. data/app/assets/js/controllers/index.js +0 -21
  64. data/app/assets/js/plutonium.js +0 -2
  65. data/build.js +0 -12
  66. data/lib/generators/pu/gem/pagy/pagy_generator.rb +0 -25
  67. data/lib/generators/pu/gem/pagy/templates/config/initializers/pagy.rb +0 -4
  68. data/lib/generators/pu/gem/rabl/rabl_generator.rb +0 -25
  69. data/lib/generators/pu/gem/rabl/templates/.keep +0 -0
  70. data/lib/generators/pu/gem/rabl/templates/config/initializers/rabl.rb +0 -60
  71. data/lib/generators/pu/gem/simple_form/simple_form_generator.rb +0 -25
  72. data/lib/generators/pu/gem/simple_form/templates/.keep +0 -0
  73. /data/{lib/generators/pu/gem/pagy/templates → app/assets/build}/.keep +0 -0
  74. /data/app/assets/{js → javascripts}/turbo/turbo_actions.js +0 -0
  75. /data/app/assets/{js → javascripts}/turbo/turbo_debug.js +0 -0
  76. /data/app/assets/{js → javascripts}/turbo/turbo_frame_monkey_patch.js +0 -0
  77. /data/app/assets/{css → stylesheets}/plutonium.css +0 -0
@@ -11,87 +11,89 @@ module PlutoniumGenerators
11
11
  protected
12
12
 
13
13
  #
14
- # Sets the ruby version for the project in .ruby-version and Gemfile to `PlutoniumGenerators::RUBY_VERSION`
14
+ # Sets the ruby version for the project in .ruby-version and Gemfile to `version`
15
15
  #
16
- # @return [void]
17
- #
18
- def set_ruby_version!
19
- log :set_ruby_version!, PlutoniumGenerators::RUBY_VERSION
20
-
21
- in_root do
22
- create_file ".ruby-version", PlutoniumGenerators::RUBY_VERSION, force: true, verbose: false
23
- gsub_file "Gemfile", /^ruby ["'].*["']/, "ruby '~> #{PlutoniumGenerators::RUBY_VERSION}'", verbose: false
24
- end
25
- end
26
-
27
- #
28
- # Adds a new gem into the Gemfile
29
- # Existing directives are updated if they do not match
30
- # When `:group` is specified, the gem is inserted into the approriate gem group.
31
- #
32
- # @param [String] name the name of the gem
33
- # @param [Hash] **kwargs set of options to append see #super
16
+ # @param [string] version semantic ruby version you want to use e.g. 3.3.0
34
17
  #
35
18
  # @return [void]
36
19
  #
37
- def gem(name, **kwargs)
38
- groups = Array(kwargs.delete(:group))
20
+ def set_ruby_version!(version)
21
+ log :set_ruby_version!, version
39
22
 
40
23
  in_root do
41
- begin
42
- # Create a temp gemfile
43
- File.rename("Gemfile", "Gemfile.bak")
44
- File.write("Gemfile", "")
45
- # Generate the directive
46
- super
47
- # Get the generated directive
48
- directive = gemfile.strip
49
- ensure
50
- # Restore our gemfile
51
- File.delete "Gemfile"
52
- File.rename "Gemfile.bak", "Gemfile"
53
- end
54
-
55
- pattern = /^# gem ['"]#{name}['"].*/
56
- if gemfile.match(pattern)
57
- # Replace commented out directive
58
- gsub_file("Gemfile", pattern, directive)
59
- break
60
- end
61
-
62
- # Remove existing directive
63
- remove_gem name
64
-
65
- # Insert the new directive
66
- if groups != []
67
- str = groups.sort.map(&:inspect).join(", ")
68
- after_sentinel = "group #{str} do\n"
69
-
70
- unless File.read("Gemfile").match?(/^#{after_sentinel}/)
71
- inject_into_file "Gemfile", "\n#{after_sentinel}end\n"
72
- end
73
- else
74
- after_sentinel = "# Project gems\n\n"
75
- unless File.read("Gemfile").match?(/^#{after_sentinel}/)
76
- inject_into_file "Gemfile", "\n#{after_sentinel}", after: /^ruby .*\n/
77
- end
78
- end
79
-
80
- inject_into_file "Gemfile", "#{directive}\n", after: /^#{after_sentinel}/
24
+ create_file ".ruby-version", version, force: true, verbose: false
25
+ gsub_file "Gemfile", /^ruby ["'].*["']/, "ruby '~> #{version}'", verbose: false
81
26
  end
82
27
  end
83
28
 
84
- #
85
- # Removes a gem and any preceeding comments from the Gemfile
86
- #
87
- # @param gem [String] the name of the gem to remove
88
- #
89
- # @return [void]
90
- #
91
- def remove_gem(gem)
92
- log :remove_gem, gem
93
- gsub_file "Gemfile", /(:?^.*#.*\n)*.*gem ['"]#{gem}['"].*\n/, "", verbose: false
94
- end
29
+ # #
30
+ # # Adds a new gem into the Gemfile
31
+ # # Existing directives are updated if they do not match
32
+ # # When `:group` is specified, the gem is inserted into the approriate gem group.
33
+ # #
34
+ # # @param [String] name the name of the gem
35
+ # # @param [Hash] **kwargs set of options to append see #super
36
+ # #
37
+ # # @return [void]
38
+ # #
39
+ # def gem(name, **kwargs)
40
+ # groups = Array(kwargs.delete(:group))
41
+
42
+ # in_root do
43
+ # begin
44
+ # # Create a temp gemfile
45
+ # File.rename("Gemfile", "Gemfile.bak")
46
+ # File.write("Gemfile", "")
47
+ # # Generate the directive
48
+ # super
49
+ # # Get the generated directive
50
+ # directive = gemfile.strip
51
+ # ensure
52
+ # # Restore our gemfile
53
+ # File.delete "Gemfile"
54
+ # File.rename "Gemfile.bak", "Gemfile"
55
+ # end
56
+
57
+ # pattern = /^# gem ['"]#{name}['"].*/
58
+ # if gemfile.match(pattern)
59
+ # # Replace commented out directive
60
+ # gsub_file("Gemfile", pattern, directive)
61
+ # break
62
+ # end
63
+
64
+ # # Remove existing directive
65
+ # remove_gem name
66
+
67
+ # # Insert the new directive
68
+ # if groups != []
69
+ # str = groups.sort.map(&:inspect).join(", ")
70
+ # after_sentinel = "group #{str} do\n"
71
+
72
+ # unless File.read("Gemfile").match?(/^#{after_sentinel}/)
73
+ # inject_into_file "Gemfile", "\n#{after_sentinel}end\n"
74
+ # end
75
+ # else
76
+ # after_sentinel = "# Project gems\n\n"
77
+ # unless File.read("Gemfile").match?(/^#{after_sentinel}/)
78
+ # inject_into_file "Gemfile", "\n#{after_sentinel}", after: /^ruby .*\n/
79
+ # end
80
+ # end
81
+
82
+ # inject_into_file "Gemfile", "#{directive}\n", after: /^#{after_sentinel}/
83
+ # end
84
+ # end
85
+
86
+ # #
87
+ # # Removes a gem and any preceeding comments from the Gemfile
88
+ # #
89
+ # # @param gem [String] the name of the gem to remove
90
+ # #
91
+ # # @return [void]
92
+ # #
93
+ # def remove_gem(gem)
94
+ # log :remove_gem, gem
95
+ # gsub_file "Gemfile", /(:?^.*#.*\n)*.*gem ['"]#{gem}['"].*\n/, "", verbose: false
96
+ # end
95
97
 
96
98
  #
97
99
  # Evaluates the given template and merges it with the project's docker-compose.yml
@@ -348,6 +350,18 @@ module PlutoniumGenerators
348
350
  File.read("Gemfile")
349
351
  end
350
352
  end
353
+
354
+ def bundle(*gems)
355
+ Bundler.with_unbundled_env do
356
+ run "bundle add #{Array(gems).join " "}"
357
+ end
358
+ end
359
+
360
+ def unbundle(*gems)
361
+ Bundler.with_unbundled_env do
362
+ run "bundle remove #{Array(gems).join " "}"
363
+ end
364
+ end
351
365
  end
352
366
  end
353
367
  end
@@ -64,12 +64,8 @@ module PlutoniumGenerators
64
64
  @prompt ||= TTY::Prompt.new
65
65
  end
66
66
 
67
- def rails?
68
- PlutoniumGenerators.rails?
69
- end
70
-
71
67
  def appname
72
- rails? ? Rails.application.class.module_parent.name : "PlutoniumGenerators"
68
+ defined?(Rails.application) ? Rails.application.class.module_parent.name : "PlutoniumGenerators"
73
69
  end
74
70
 
75
71
  def app_name
@@ -1,7 +1,15 @@
1
1
  require "zeitwerk"
2
2
 
3
3
  loader = Zeitwerk::Loader.for_gem # (warn_on_extra_files: false)
4
+ loader.inflector.inflect(
5
+ "cli" => "CLI"
6
+ )
4
7
  loader.setup
5
8
 
6
9
  module PlutoniumGenerators
10
+ class << self
11
+ def cli?
12
+ ENV["PU_CLI"] == "1"
13
+ end
14
+ end
7
15
  end
@@ -18,8 +18,7 @@ module Pu
18
18
 
19
19
  def add_rodauth
20
20
  Bundler.with_unbundled_env do
21
- run "bundle add bcrypt"
22
- run "bundle add rodauth-rails"
21
+ run "bundle add bcrypt rodauth-rails"
23
22
  end
24
23
  end
25
24
 
@@ -9,7 +9,7 @@ module Plutonium
9
9
  end
10
10
 
11
11
  def permitted_for(policy)
12
- Collection.new(@collection.select { |name, action| policy.send :"#{action.name}?" })
12
+ Collection.new(@collection.select { |name, action| policy.send_with_report :"#{action.name}?" })
13
13
  end
14
14
 
15
15
  def collection_actions
@@ -42,7 +42,7 @@ module Plutonium
42
42
  end
43
43
 
44
44
  def permitted_attributes
45
- @permitted_attributes ||= current_policy.send :"permitted_attributes_for_#{action_name}"
45
+ @permitted_attributes ||= current_policy.send_with_report :"permitted_attributes_for_#{action_name}"
46
46
  end
47
47
 
48
48
  def current_policy
@@ -52,9 +52,9 @@ module Plutonium
52
52
  end
53
53
  end
54
54
 
55
- def parent_policy
56
- @parent_policy ||= policy(current_parent) if current_parent.present?
57
- end
55
+ # def parent_policy
56
+ # @parent_policy ||= policy(current_parent) if current_parent.present?
57
+ # end
58
58
  end
59
59
  end
60
60
  end
@@ -10,7 +10,7 @@ module Plutonium
10
10
  @user_options = user_options
11
11
  end
12
12
 
13
- def render(f, record, **)
13
+ def render(view_context, f, record, **)
14
14
  raise NotImplementedError, "#{self.class}#render"
15
15
  end
16
16
 
@@ -0,0 +1,57 @@
1
+ module Plutonium
2
+ module Core
3
+ module Fields
4
+ module Inputs
5
+ class NestedInput < Base
6
+ include Plutonium::Core::Definers::InputDefiner
7
+
8
+ attr_reader :inputs, :resource_class
9
+
10
+ def initialize(name, inputs:, resource_class:, allow_destroy:, update_only:, limit:, **user_options)
11
+ @inputs = inputs
12
+ @resource_class = resource_class
13
+ @allow_destroy = allow_destroy
14
+ @update_only = update_only
15
+ @limit = limit
16
+
17
+ super(name, **user_options)
18
+ end
19
+
20
+ def render(view_context, f, record, **opts)
21
+ opts = options.deep_merge opts
22
+ view_context.render_component :nested_resource_form_fields, form: f, **opts
23
+ end
24
+
25
+ def collect(params)
26
+ attributes = {}
27
+ params[param].each do |index, nested_params|
28
+ collected = defined_inputs.collect_all(nested_params)
29
+ collected[:id] = nested_params[:id] if nested_params.key?(:id) && !@update_only
30
+ collected[:_destroy] = nested_params[:_destroy] if @allow_destroy
31
+ attributes[index] = collected
32
+ end
33
+
34
+ {param => attributes}
35
+ end
36
+
37
+ private
38
+
39
+ def param = :"#{name}_attributes"
40
+
41
+ def input_options = {
42
+ name:,
43
+ resource_class:,
44
+ allow_destroy: @allow_destroy,
45
+ update_only: @update_only,
46
+ limit: @limit,
47
+ inputs: defined_inputs
48
+ }
49
+
50
+ def defined_inputs
51
+ @defined_inputs ||= defined_inputs_for(*inputs)
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -6,7 +6,7 @@ module Plutonium
6
6
  def initialize(*)
7
7
  end
8
8
 
9
- def render(f, record, **)
9
+ def render(view_context, f, record, **)
10
10
  end
11
11
 
12
12
  def collect(params)
@@ -3,7 +3,7 @@ module Plutonium
3
3
  module Fields
4
4
  module Inputs
5
5
  class PhoneInput < SimpleFormInput
6
- # def render(f, record, **opts)
6
+ # def render(view_context, f, record, **opts)
7
7
  # opts = options.deep_merge opts
8
8
  # opts.delete(:as)
9
9
  # f.input name, **opts
@@ -3,7 +3,7 @@ module Plutonium
3
3
  module Fields
4
4
  module Inputs
5
5
  class PolymorphicBelongsToAssociationInput < SimpleFormAssociationInput
6
- def render(f, record, **opts)
6
+ def render(view_context, f, record, **opts)
7
7
  opts = options.deep_merge opts
8
8
  f.input param, **opts
9
9
  end
@@ -10,7 +10,7 @@ module Plutonium
10
10
  super(name, **user_options)
11
11
  end
12
12
 
13
- def render(f, record, **opts)
13
+ def render(view_context, f, record, **opts)
14
14
  opts = options.deep_merge opts
15
15
  f.association name, **opts
16
16
  end
@@ -3,7 +3,7 @@ module Plutonium
3
3
  module Fields
4
4
  module Inputs
5
5
  class SimpleFormInput < Base
6
- def render(f, record, **opts)
6
+ def render(view_context, f, record, **opts)
7
7
  opts = options.deep_merge opts
8
8
  f.input name, **opts
9
9
  end
@@ -17,10 +17,6 @@ module Plutonium
17
17
  add_view_paths_initializer.instance_variable_set(:@block, ->(app) {})
18
18
  end
19
19
  end
20
-
21
- def scoped_to_entity?
22
- raise NotImplementedError, "scoped_to_entity?"
23
- end
24
20
  end
25
21
  end
26
22
  end
@@ -2,7 +2,15 @@ require "view_component"
2
2
 
3
3
  module Plutonium
4
4
  class Railtie < Rails::Railtie
5
- initializer "plutonium.assets_server" do
5
+ config.plutonium = ActiveSupport::OrderedOptions.new
6
+
7
+ initializer "plutonium.append_assets_path" do |app|
8
+ config.to_prepare do
9
+ Rails.application.config.assets.paths << Plutonium.root.join("app/assets/build").to_s
10
+ end
11
+ end
12
+
13
+ initializer "plutonium.asset_server" do
6
14
  # setup a middleware to serve our assets
7
15
  config.app_middleware.insert_before(
8
16
  ActionDispatch::Static,
@@ -17,7 +25,7 @@ module Plutonium
17
25
  )
18
26
  end
19
27
 
20
- initializer "plutonium.view_components" do
28
+ initializer "plutonium.view_components_capture_compat" do
21
29
  config.view_component.capture_compatibility_patch_enabled = true
22
30
  end
23
31
  end
@@ -6,6 +6,12 @@ module Plutonium
6
6
  class Scope < Plutonium::Policy::Scope
7
7
  end
8
8
 
9
+ def send_with_report(method)
10
+ raise NotImplementedError, "#{self.class.name} does not implement the required #{method}" unless respond_to? method
11
+
12
+ send method
13
+ end
14
+
9
15
  # Core actions
10
16
 
11
17
  def create?
@@ -37,6 +37,41 @@ module Plutonium
37
37
  define_action Plutonium::Core::Actions::InteractiveAction.new(name, interaction:, **)
38
38
  end
39
39
 
40
+ # TODO: move this to its own definer
41
+ def define_nested_input(name, inputs:, model_class: nil, **options)
42
+ nested_attribute_options = resource_class.all_nested_attributes_options[name]
43
+
44
+ nested_attribute_options_class = nested_attribute_options&.[](:class)
45
+ if nested_attribute_options_class.nil? && model_class.nil?
46
+ raise ArgumentError, "model_class is required if your field is not an association or is polymorphic"
47
+ end
48
+ model_class ||= nested_attribute_options_class
49
+
50
+ macro = nested_attribute_options&.[](:macro)
51
+ allow_destroy = nested_attribute_options&.[](:allow_destroy).presence
52
+ update_only = nested_attribute_options&.[](:update_only).presence
53
+ limit = if macro == :has_one
54
+ 1
55
+ elsif options.key?(:limit)
56
+ options[:limit]
57
+ else
58
+ nested_attribute_options&.[](:limit)
59
+ end
60
+
61
+ input = Plutonium::Core::Fields::Inputs::NestedInput.new(
62
+ name,
63
+ inputs:,
64
+ allow_destroy: options.key?(:allow_destroy) ? options[:allow_destroy] : allow_destroy,
65
+ update_only: options.key?(:update_only) ? options[:update_only] : update_only,
66
+ limit: limit,
67
+ resource_class: model_class,
68
+ **options
69
+ )
70
+ yield input if block_given?
71
+
72
+ define_input name, input:
73
+ end
74
+
40
75
  def resource_class = context.resource_class
41
76
  end
42
77
  end
@@ -117,6 +117,23 @@ module Plutonium
117
117
  @has_many_association_routes ||= reflect_on_all_associations(:has_many).map { |assoc| assoc.klass.model_name.plural }
118
118
  end
119
119
 
120
+ def all_nested_attributes_options
121
+ unless Rails.env.local?
122
+ return @all_nested_attributes_options if defined?(@all_nested_attributes_options)
123
+ end
124
+
125
+ @all_nested_attributes_options = reflect_on_all_associations.map do |association|
126
+ setter_method = "#{association.name}_attributes="
127
+ if method_defined?(setter_method)
128
+ [association.name, {
129
+ **nested_attributes_options[association.name],
130
+ macro: association.macro,
131
+ class: association.polymorphic? ? nil : association.klass
132
+ }]
133
+ end
134
+ end.compact.to_h
135
+ end
136
+
120
137
  #
121
138
  # Returns the strong parameters definition for the given attribute names
122
139
  #
@@ -127,6 +144,8 @@ module Plutonium
127
144
  #
128
145
  def strong_parameters_for(*attributes)
129
146
  # attributes that are passed but we do not have a model/database backed definition for e.g. virtual attributes.
147
+ # if they are passed and we are not expecting them, our inputs will filter them out as they apply an additional level
148
+ # of filtering
130
149
  unbacked = attributes - strong_parameters_definition.keys
131
150
 
132
151
  # attributes backed by some model/database definition
@@ -147,8 +166,13 @@ module Plutonium
147
166
  private
148
167
 
149
168
  def strong_parameters_definition
150
- # @strong_parameters ||= begin
169
+ unless Rails.env.local?
170
+ return @strong_parameters if defined?(@strong_parameters)
171
+ end
172
+
151
173
  @strong_parameters = begin
174
+ # Columns
175
+
152
176
  content_column_parameters = content_column_field_names.map do |name|
153
177
  column = columns_hash[name.to_s]
154
178
 
@@ -160,21 +184,30 @@ module Plutonium
160
184
  end
161
185
  parameters = content_column_parameters.to_h
162
186
 
163
- # TODO: add nested support
187
+ # Associations
164
188
 
165
- # TODO:
166
189
  parameters.merge! reflect_on_all_associations(:belongs_to)
167
190
  .map { |reflection|
168
- input_param = (reflection.respond_to?(:options) && reflection.options[:foreign_key]) || :"#{reflection.name}_id"
191
+ input_param = reflection.respond_to?(:options) ? reflection.options[:foreign_key] : :"#{reflection.name}_id"
169
192
  [reflection.name, {input_param => nil}]
170
193
  }
171
194
  .to_h
172
195
 
173
- parameters.merge! has_one_association_field_names.map { |name| [name, {name => nil}] }.to_h
196
+ parameters.merge! has_many_association_field_names
197
+ .map { |name| [name, {"#{name.to_s.singularize}_ids": []}] }
198
+ .to_h
199
+
200
+ # Attachments
201
+
202
+ parameters.merge! has_many_attached_field_names.map { |name| [name, {name => []}] }.to_h
203
+
174
204
  parameters.merge! has_one_attached_field_names.map { |name| [name, {name => nil}] }.to_h
175
205
 
176
- parameters.merge! has_many_association_field_names.map { |name| [name, {"#{name.to_s.singularize}_ids": []}] }.to_h
177
- parameters.merge! has_many_attached_field_names.map { |name| [name, {name: []}] }.to_h
206
+ # Nested Attributes
207
+
208
+ parameters.merge! all_nested_attributes_options.keys
209
+ .map { |name| [name, {"#{name}_attributes" => {}}] }
210
+ .to_h
178
211
 
179
212
  # e.g.
180
213
  # {:name=>{:name=>nil}, :cover_image=>{:cover_image=>nil}, :user=>{:user_id=>nil} :comments=>{:comment_ids=>[]}}
@@ -1,3 +1,3 @@
1
1
  module Plutonium
2
- VERSION = "0.8.0"
2
+ VERSION = "0.9.1"
3
3
  end
data/lib/plutonium.rb CHANGED
@@ -21,28 +21,31 @@ module Plutonium
21
21
 
22
22
  def self.stylesheet_link
23
23
  if Plutonium::Config.development
24
- file = JSON.parse(File.read(root.join("css.manifest")))["plutonium-dev.css"]
25
- "/plutonium-assets/build/#{file}"
24
+ base_dir = "/plutonium-assets/build"
25
+ manifest = "css.dev.manifest"
26
+ filename = "plutonium-dev.css"
26
27
  else
27
- raise NotImplementedError, "TODO: implement asset resolution for prod"
28
- # @stylesheet ||= begin
29
- # file = JSON.parse(File.read(root.join("css.manifest")))["plutonium.css"]
30
- # "/plutonium-assets/#{file}"
31
- # end
28
+ base_dir = "/plutonium-assets"
29
+ manifest = "css.manifest"
30
+ filename = "plutonium.css"
32
31
  end
32
+
33
+ file = JSON.parse(File.read(root.join(manifest)))[filename]
34
+ "#{base_dir}/#{file}"
33
35
  end
34
36
 
35
37
  def self.script_link
38
+ filename = "plutonium-app.js"
36
39
  if Plutonium::Config.development
37
- file = JSON.parse(File.read(root.join("js.manifest")))["plutonium.js"]
38
- "/plutonium-assets/build/#{file}"
40
+ base_dir = "/plutonium-assets/build"
41
+ manifest = "js.dev.manifest"
39
42
  else
40
- raise NotImplementedError, "TODO: implement asset resolution for prod"
41
- # @stylesheet ||= begin
42
- # file = JSON.parse(File.read(root.join("css.manifest")))["plutonium.css"]
43
- # "/plutonium-assets/#{file}"
44
- # end
43
+ base_dir = "/plutonium-assets"
44
+ manifest = "js.manifest"
45
45
  end
46
+
47
+ file = JSON.parse(File.read(root.join(manifest)))[filename]
48
+ "#{base_dir}/#{file}"
46
49
  end
47
50
  end
48
51
 
data/package.json CHANGED
@@ -14,8 +14,9 @@
14
14
  "tailwindcss": "^3.4.1"
15
15
  },
16
16
  "scripts": {
17
- "watch": "postcss app/assets/css/plutonium.css -o public/plutonium-assets/build/plutonium-dev.css --watch",
18
- "scripts": "node build.js",
19
- "build": "postcss app/assets/css/plutonium.css -o public/plutonium-assets/build/plutonium.css --watch"
17
+ "css:dev": "postcss app/assets/stylesheets/plutonium.css -o public/plutonium-assets/build/plutonium-dev.css --watch",
18
+ "js:dev": "node esbuild.config.js",
19
+ "css:prod": "postcss app/assets/stylesheets/plutonium.css -o public/plutonium-assets/plutonium.css --prod",
20
+ "js:prod": "node esbuild.config.js --prod"
20
21
  }
21
22
  }
data/postcss.config.js CHANGED
@@ -5,7 +5,7 @@ module.exports = {
5
5
  'postcss-hash': {
6
6
  algorithm: 'sha256',
7
7
  trim: 20,
8
- manifest: './css.manifest'
8
+ manifest: process.argv.includes("--prod") ? './css.manifest' : './css.dev.manifest'
9
9
  },
10
10
  }
11
11
  }