lesli 5.0.24 → 5.1.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 (65) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/lesli/{item → items}/activities_controller.rb +1 -1
  3. data/app/controllers/lesli/{item → items}/discussions_controller.rb +3 -3
  4. data/app/controllers/lesli/{item → items}/tasks_controller.rb +3 -3
  5. data/app/helpers/lesli/customization_helper.rb +1 -1
  6. data/app/helpers/lesli/html_helper.rb +1 -1
  7. data/app/models/concerns/lesli/{item → items}/activities.rb +2 -2
  8. data/app/models/concerns/lesli/{item → items}/discussions.rb +2 -2
  9. data/app/models/concerns/lesli/{item → items}/tasks.rb +2 -2
  10. data/app/models/lesli/application_lesli_record.rb +1 -1
  11. data/app/models/lesli/{item → items}/activity.rb +1 -1
  12. data/app/models/lesli/{item → items}/discussion.rb +1 -1
  13. data/app/models/lesli/{item → items}/task.rb +1 -1
  14. data/app/views/lesli/partials/_application-lesli-assets.html.erb +2 -0
  15. data/config/brakeman.yml +2 -13
  16. data/lib/generators/lesli/base_generator.rb +172 -0
  17. data/lib/generators/lesli/controller/controller_generator.rb +40 -0
  18. data/lib/generators/lesli/controller/templates/controller.rb.tt +86 -0
  19. data/lib/generators/lesli/model/model_generator.rb +44 -0
  20. data/lib/generators/lesli/model/templates/model.rb.tt +16 -0
  21. data/lib/generators/lesli/scaffold/scaffold_generator.rb +47 -0
  22. data/lib/generators/lesli/service/service_generator.rb +40 -0
  23. data/lib/generators/lesli/service/templates/service.rb.tt +44 -0
  24. data/lib/generators/lesli/views/templates/_form.html.erb.tt +22 -0
  25. data/lib/generators/lesli/views/templates/index.html.erb.tt +17 -0
  26. data/lib/generators/lesli/views/templates/new.html.erb.tt +4 -0
  27. data/lib/generators/lesli/views/templates/show.html.erb.tt +22 -0
  28. data/lib/generators/lesli/views/views_generator.rb +106 -0
  29. data/lib/lesli/engine.rb +1 -23
  30. data/lib/lesli/router.rb +1 -1
  31. data/lib/lesli/version.rb +2 -2
  32. data/lib/migrate/common.rb +2 -2
  33. data/lib/migrate/items/activity_structure.rb +1 -1
  34. data/lib/migrate/items/attachment_structure.rb +1 -1
  35. data/lib/migrate/items/discussion_structure.rb +1 -1
  36. data/lib/migrate/items/subscriber_structure.rb +1 -1
  37. data/lib/migrate/items/task_structure.rb +1 -1
  38. data/lib/migrate/items/version_structure.rb +1 -1
  39. data/lib/tasks/lesli/db.rake +6 -6
  40. data/lib/tasks/lesli_tasks.rake +7 -32
  41. data/readme.md +3 -3
  42. metadata +57 -63
  43. data/app/assets/config/lesli_manifest.js +0 -42
  44. data/app/assets/images/lesli/brand/app-auth.svg +0 -9
  45. data/app/assets/images/lesli/brand/app-icon.svg +0 -48
  46. data/app/assets/images/lesli/brand/app-logo.png +0 -0
  47. data/app/assets/images/lesli/brand/app-logo.svg +0 -4
  48. data/app/assets/images/lesli/brand/favicon.png +0 -0
  49. data/app/assets/images/lesli/brand/favicon.svg +0 -61
  50. data/app/assets/images/lesli/brand/login-background.jpg +0 -0
  51. data/app/assets/images/lesli/brand/register-background.jpg +0 -0
  52. data/app/assets/javascripts/lesli/application.js +0 -1
  53. data/config/importmap.rb +0 -1
  54. data/lib/generators/application_lesli_generator_base.rb +0 -164
  55. data/lib/generators/lesli/spec/USAGE +0 -8
  56. data/lib/generators/lesli/spec/spec_generator.rb +0 -22
  57. data/lib/generators/lesli/spec/templates/spec-factory.template +0 -17
  58. data/lib/generators/lesli/spec/templates/spec-model.template +0 -70
  59. data/lib/generators/lesli/view/USAGE +0 -8
  60. data/lib/generators/lesli/view/templates/spec-factory.template +0 -17
  61. data/lib/generators/lesli/view/templates/spec-model.template +0 -70
  62. data/lib/generators/lesli/view/view_generator.rb +0 -22
  63. data/lib/lesli/r_spec.rb +0 -43
  64. data/lib/scss/_apps.scss +0 -94
  65. data/lib/scss/application.scss +0 -34
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a56fbd90769c845789e9fc2097da330344938d31db26be4da238adae6e18ded8
4
- data.tar.gz: 840585ccd69d395bde16bbd9b41e4b33e4cd41343e09f35b12fe7f5452e6b513
3
+ metadata.gz: d8bcebb6d3d2d5ea33fe19e472a0e4332a6bf3da560d1d190900433cc98ad92c
4
+ data.tar.gz: 8cbbd81d6e4a08666e9846226e3b0e48ed87a894ad420599dbc7362572409cb8
5
5
  SHA512:
6
- metadata.gz: 20d6570450c48ca8c79132403144d12c7a718dd6b91c03e346899badeacad0d2627543f0f5b5dd98274edbb600b6073c2147ac27ef09a694acd0a3d257466a19
7
- data.tar.gz: 6ab41da8a99d0b615071dedce1a4f020be93d4ffe85de5ae48a6fd5538182cec1194ff38b2daa79a16d901441463f5e376e67c403baf4a1e09509e1a3539c09c
6
+ metadata.gz: e35418f65926ed377dabae4c838c6e1abbca690727e12aeb0735262f93ce6fb1533b29915c5378acbe06d72884fc9b36b0d8e04c83aa5ad868bf7891ac7fed33
7
+ data.tar.gz: 36a495f49d761b7ba6824a9ef84baa6ac425028bff9fc9592035df333c48b96204db1366b29ccb9e514dbf96440e7eb8239f8d89b98d67c0637be098afdf4836
@@ -31,7 +31,7 @@ Building a better future, one line of code at a time.
31
31
  =end
32
32
 
33
33
  module Lesli
34
- module Item
34
+ module Items
35
35
  class ActivitiesController < ApplicationLesliController
36
36
  end
37
37
  end
@@ -31,7 +31,7 @@ Building a better future, one line of code at a time.
31
31
  =end
32
32
 
33
33
  module Lesli
34
- module Item
34
+ module Items
35
35
  class DiscussionsController < ApplicationLesliController
36
36
  before_action :set_discussion, only: %i[show update]
37
37
  before_action :set_discussable, only: %i[index create]
@@ -57,7 +57,7 @@ module Lesli
57
57
  respond_with_lesli(:turbo => [
58
58
  stream_notification_success("Discussion created"),
59
59
  turbo_stream.prepend("#{scope_key}-lesli-items-discussions-list") do
60
- LesliView::Item::Discussion.new(discussion).render_in(view_context)
60
+ LesliView::Items::Discussion.new(discussion).render_in(view_context)
61
61
  end
62
62
  ])
63
63
  else
@@ -73,7 +73,7 @@ module Lesli
73
73
  respond_with_lesli(:turbo => [
74
74
  stream_notification_success("Discussion updated #{@discussable}"),
75
75
  turbo_stream.replace(helpers.dom_id(@discussion, scope_key)) do
76
- LesliView::Item::Discussion.new(@discussion, scope_key).render_in(view_context)
76
+ LesliView::Items::Discussion.new(@discussion, scope_key).render_in(view_context)
77
77
  end
78
78
  ])
79
79
  end
@@ -31,7 +31,7 @@ Building a better future, one line of code at a time.
31
31
  =end
32
32
 
33
33
  module Lesli
34
- module Item
34
+ module Items
35
35
  class TasksController < ApplicationLesliController
36
36
  before_action :set_task, only: %i[show update]
37
37
  before_action :set_taskable, only: %i[index create]
@@ -57,7 +57,7 @@ module Lesli
57
57
  respond_with_lesli(:turbo => [
58
58
  stream_notification_success("Task created"),
59
59
  turbo_stream.prepend("#{scope_key}-lesli-items-tasks-list") do
60
- LesliView::Item::Task.new(task, scope_key).render_in(view_context)
60
+ LesliView::Items::Task.new(task, scope_key).render_in(view_context)
61
61
  end
62
62
  ])
63
63
  else
@@ -73,7 +73,7 @@ module Lesli
73
73
  respond_with_lesli(:turbo => [
74
74
  stream_notification_success("Task updated #{@taskable}"),
75
75
  turbo_stream.replace(helpers.dom_id(@task, scope_key)) do
76
- LesliView::Item::Task.new(@task, scope_key).render_in(view_context)
76
+ LesliView::Items::Task.new(@task, scope_key).render_in(view_context)
77
77
  end
78
78
  ])
79
79
  end
@@ -45,7 +45,7 @@ module Lesli
45
45
  def customization_instance_logo(tag: false, logo: "app-logo", variant: "light", mode: "web",
46
46
  options: { alt: "Logo" })
47
47
  # loading logo from builder assets
48
- logo_path = "#{lesli_instance_code}/brand/#{logo}.svg"
48
+ logo_path = "lesli_assets/brand/#{logo}.svg"
49
49
 
50
50
  # load favicon as PNG for better compatibility between web browsers
51
51
  #logo_path = "#{lesli_instance_code}/brand/#{logo}.png" if logo == "favicon"
@@ -35,7 +35,7 @@ module Lesli
35
35
 
36
36
  # Prints link tags to add favicon to websites
37
37
  def lesli_favicon
38
- icon_path = image_url("lesli/brand/favicon.svg")
38
+ icon_path = image_url("lesli_assets/brand/favicon.svg")
39
39
  safe_join([
40
40
  tag.link(href: icon_path, rel: "alternate icon"),
41
41
  tag.link(href: icon_path, rel: "icon", type: "image/svg+xml"),
@@ -31,7 +31,7 @@ Building a better future, one line of code at a time.
31
31
  =end
32
32
 
33
33
  module Lesli
34
- module Item
34
+ module Items
35
35
  module Activities
36
36
  extend ActiveSupport::Concern
37
37
 
@@ -48,7 +48,7 @@ module Lesli
48
48
  klass = if use
49
49
  use.to_s.constantize
50
50
  else
51
- "#{name.deconstantize}::Item::Activity".constantize
51
+ "#{name.deconstantize}::Items::Activity".constantize
52
52
  end
53
53
 
54
54
  self.lesli_activities_class = klass
@@ -31,7 +31,7 @@ Building a better future, one line of code at a time.
31
31
  =end
32
32
 
33
33
  module Lesli
34
- module Item
34
+ module Items
35
35
  module Discussions
36
36
  extend ActiveSupport::Concern
37
37
 
@@ -53,7 +53,7 @@ module Lesli
53
53
  klass = if use
54
54
  use.to_s.constantize
55
55
  else
56
- "#{name.deconstantize}::Item::Discussion".constantize
56
+ "#{name.deconstantize}::Items::Discussion".constantize
57
57
  end
58
58
 
59
59
  self.lesli_discussions_class = klass
@@ -31,7 +31,7 @@ Building a better future, one line of code at a time.
31
31
  =end
32
32
 
33
33
  module Lesli
34
- module Item
34
+ module Items
35
35
  module Tasks
36
36
  extend ActiveSupport::Concern
37
37
 
@@ -53,7 +53,7 @@ module Lesli
53
53
  klass = if use
54
54
  use.to_s.constantize
55
55
  else
56
- "#{name.deconstantize}::Item::Task".constantize
56
+ "#{name.deconstantize}::Items::Task".constantize
57
57
  end
58
58
 
59
59
  self.lesli_tasks_class = klass
@@ -37,7 +37,7 @@ module Lesli
37
37
 
38
38
  CHARSET = "ABCDEFGHJKLMNPQRSTUVWXYZ"
39
39
 
40
- def generate_resource_uid(prefix:'Lesli', length:4)
40
+ def generate_resource_uid(prefix:nil, length:4)
41
41
 
42
42
  year = Time.current.year % 100
43
43
  month = Time.current.month
@@ -31,7 +31,7 @@ Building a better future, one line of code at a time.
31
31
  =end
32
32
 
33
33
  module Lesli
34
- module Item
34
+ module Items
35
35
  class Activity < ApplicationRecord
36
36
  self.abstract_class = true
37
37
  belongs_to :user, class_name: "Lesli::User"
@@ -1,5 +1,5 @@
1
1
  module Lesli
2
- module Item
2
+ module Items
3
3
  class Discussion < ApplicationRecord
4
4
  self.abstract_class = true
5
5
  belongs_to :user, class_name: "Lesli::User"
@@ -31,7 +31,7 @@ Building a better future, one line of code at a time.
31
31
  =end
32
32
 
33
33
  module Lesli
34
- module Item
34
+ module Items
35
35
  class Task < ApplicationRecord
36
36
  self.abstract_class = true
37
37
  belongs_to :user, class_name: "Lesli::User"
@@ -50,9 +50,11 @@ Building a better future, one line of code at a time.
50
50
 
51
51
 
52
52
  <%# Loading stylesheets from engines %>
53
+ <%#= stylesheet_link_tag(lesli_stylesheet_path(:lesli_assets, 'tailwind'), media: "all") %>
53
54
  <%= stylesheet_link_tag(lesli_stylesheet_path(:lesli_assets), media: "all") %>
54
55
  <%= stylesheet_link_tag(lesli_stylesheet_path(), media: "all") %>
55
56
 
57
+
56
58
  <%# Loading javascripts from engines %>
57
59
  <%= javascript_include_tag(lesli_stylesheet_path(:lesli_assets, 'application'), :defer => "defer") %>
58
60
  <%= yield(:application_lesli_javascript) %>
data/config/brakeman.yml CHANGED
@@ -4,18 +4,11 @@
4
4
 
5
5
  # Files and Directories to Skip
6
6
  skip_files:
7
- - "tmp/**/*" # Skip temporary files
8
- - "vendor/**/*" # Skip vendor folder
9
- - "node_modules/**/*" # Skip global node_modules
10
- - "engines/Lesli/node_modules/"
11
- - "engines/Lesli/app/items/*"
12
- - "engines/Lesli/app/models/lesli/cloud_object/"
13
- - "enginesdev/"
14
7
 
15
8
  # Warnings to Ignore (List Warning Codes)
16
9
  ignore_warnings:
17
- - "SQLi" # Example: Ignore false-positive SQL injection warnings
18
- - "WeakHash" # Ignore warnings about weak hashing if you're using MD5 intentionally
10
+ # - "SQLi" # Example: Ignore false-positive SQL injection warnings
11
+ # - "WeakHash" # Ignore warnings about weak hashing if you're using MD5 intentionally
19
12
 
20
13
  # Additional Checks
21
14
  checks_to_run:
@@ -26,10 +19,6 @@ checks_to_run:
26
19
  - "FileAccess"
27
20
  - "UnmaintainedDependency"
28
21
 
29
- # Additional Paths to Search for Code
30
- additional_libs_path:
31
- - "engines/Lesli/app/lib"
32
-
33
22
  # Confidence Levels to Report
34
23
  min_confidence: 2 # 0 (all warnings), 1 (medium), 2 (high)
35
24
 
@@ -0,0 +1,172 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/generators"
4
+
5
+ module Lesli
6
+ module Generators
7
+ # Shared base generator for all Lesli generators.
8
+ #
9
+ # This class centralizes the logic used by all generators, such as:
10
+ #
11
+ # - engine name detection
12
+ # - engine namespace detection
13
+ # - domain name normalization
14
+ # - resource naming helpers
15
+ #
16
+ # This avoids duplicating the same helper methods in every generator.
17
+ class BaseGenerator < Rails::Generators::NamedBase
18
+
19
+ private
20
+
21
+ # Returns the current engine folder name in snake_case.
22
+ #
23
+ # Examples:
24
+ # "/code/lesli_support" -> "lesli_support"
25
+ # "/code/my_engine" -> "my_engine"
26
+ # "/code/store" -> "store"
27
+ def engine_name
28
+ File.basename(ENGINE_ROOT.to_s).underscore
29
+ end
30
+
31
+ # Returns the current engine Ruby namespace in CamelCase.
32
+ #
33
+ # Examples:
34
+ # "lesli_support" -> "LesliSupport"
35
+ # "my_engine" -> "MyEngine"
36
+ # "store" -> "Store"
37
+ def engine_namespace
38
+ engine_name.camelize
39
+ end
40
+
41
+ # Returns the domain name derived from the engine namespace.
42
+ #
43
+ # Rules:
44
+ # - If the engine starts with "Lesli", remove that prefix
45
+ # - Otherwise use the full engine namespace
46
+ # - Convert the result to snake_case
47
+ #
48
+ # Examples:
49
+ # "LesliSupport" -> "support"
50
+ # "LesliCalendar" -> "calendar"
51
+ # "MyEngine" -> "my_engine"
52
+ # "Store" -> "store"
53
+ def engine_domain_name
54
+ namespace = engine_namespace
55
+
56
+ if namespace.start_with?("Lesli") && namespace != "Lesli"
57
+ namespace.delete_prefix("Lesli").underscore
58
+ else
59
+ namespace.underscore
60
+ end
61
+ end
62
+
63
+ # Returns the singular normalized resource name.
64
+ #
65
+ # Examples:
66
+ # "tickets" -> "ticket"
67
+ # "products" -> "product"
68
+ # "store" -> "store"
69
+ #
70
+ # This is the main workaround for NamedBase, because by default
71
+ # a plural input like "products" may produce class_name = "Products".
72
+ def resource_name
73
+ name.to_s.singularize.underscore
74
+ end
75
+
76
+ # Returns the plural normalized resource name.
77
+ #
78
+ # Examples:
79
+ # "ticket" -> "tickets"
80
+ # "product" -> "products"
81
+ def resource_collection_name
82
+ resource_name.pluralize
83
+ end
84
+
85
+ # Returns the Ruby model class name.
86
+ #
87
+ # Examples:
88
+ # "ticket" -> "Ticket"
89
+ # "product" -> "Product"
90
+ def resource_class_name
91
+ resource_name.camelize
92
+ end
93
+
94
+ # Returns the plural controller class name.
95
+ #
96
+ # Examples:
97
+ # "tickets" -> "Tickets"
98
+ # "products" -> "Products"
99
+ def controller_class_name
100
+ resource_collection_name.camelize
101
+ end
102
+
103
+ # Returns the service class name.
104
+ #
105
+ # Examples:
106
+ # "Ticket" -> "TicketService"
107
+ # "Product" -> "ProductService"
108
+ def service_class_name
109
+ "#{resource_class_name}Service"
110
+ end
111
+
112
+ # Returns the resource instance variable name.
113
+ #
114
+ # Examples:
115
+ # "ticket" -> "@ticket"
116
+ # "product" -> "@product"
117
+ def resource_instance
118
+ "@#{resource_name}"
119
+ end
120
+
121
+ # Returns the resource collection instance variable name.
122
+ #
123
+ # Examples:
124
+ # "tickets" -> "@tickets"
125
+ # "products" -> "@products"
126
+ def resource_collection_instance
127
+ "@#{resource_collection_name}"
128
+ end
129
+
130
+ # Returns the before_action setter method name.
131
+ #
132
+ # Examples:
133
+ # "ticket" -> "set_ticket"
134
+ # "product" -> "set_product"
135
+ def set_resource_method_name
136
+ "set_#{resource_name}"
137
+ end
138
+
139
+ # Returns the params method name.
140
+ #
141
+ # Examples:
142
+ # "ticket" -> "ticket_params"
143
+ # "product" -> "product_params"
144
+ def params_method_name
145
+ "#{resource_name}_params"
146
+ end
147
+
148
+ # Returns the namespaced model class name.
149
+ #
150
+ # Examples:
151
+ # "LesliSupport::Ticket"
152
+ # "MyEngine::Product"
153
+ def namespaced_resource_class_name
154
+ "#{engine_namespace}::#{resource_class_name}"
155
+ end
156
+
157
+ # Returns only the attribute names passed to the generator.
158
+ #
159
+ # Example:
160
+ # ["subject:string", "owner_id:integer"] -> ["subject", "owner_id"]
161
+ def permitted_attributes
162
+ return [] unless respond_to?(:attributes)
163
+
164
+ attributes.map(&:name)
165
+ end
166
+
167
+ def namespaced_model_name
168
+ "#{engine_namespace}::#{resource_class_name}"
169
+ end
170
+ end
171
+ end
172
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/generators"
4
+ require_relative "../base_generator"
5
+
6
+ module Lesli
7
+ module Generators
8
+ # Generates a Lesli-style controller inside the current engine.
9
+ class ControllerGenerator < BaseGenerator
10
+ argument :attributes, type: :array, default: [], banner: "field:type field:type"
11
+
12
+ source_root File.expand_path("templates", __dir__)
13
+
14
+ # Creates the controller file from the template.
15
+ def create_controller_file
16
+ template "controller.rb.tt", controller_file_path
17
+ end
18
+
19
+ private
20
+
21
+ # Returns the controller directory inside the engine namespace.
22
+ #
23
+ # Example:
24
+ # app/controllers/lesli_support
25
+ # app/controllers/my_engine
26
+ # app/controllers/store
27
+ def controller_directory
28
+ File.join(ENGINE_ROOT, "app/controllers", engine_name)
29
+ end
30
+
31
+ # Returns the final controller file path.
32
+ #
33
+ # Example:
34
+ # app/controllers/lesli_support/tickets_controller.rb
35
+ def controller_file_path
36
+ File.join(controller_directory, "#{resource_collection_name}_controller.rb")
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,86 @@
1
+ # frozen_string_literal: true
2
+
3
+ module <%= engine_namespace %>
4
+ class <%= controller_class_name %>Controller < ApplicationController
5
+ before_action :<%= set_resource_method_name %>, only: [:show, :edit, :update, :destroy]
6
+
7
+ def index
8
+ <%= resource_collection_instance %> = respond_with_pagination(
9
+ <%= service_class_name %>.new(current_user, query).index
10
+ )
11
+ end
12
+
13
+ def show
14
+ <%= resource_instance %> = <%= resource_instance %>.show
15
+ end
16
+
17
+ def new
18
+ <%= resource_instance %> = <%= resource_class_name %>.new
19
+ end
20
+
21
+ def edit
22
+ end
23
+
24
+ def create
25
+ <%= resource_name %> = <%= service_class_name %>.new(current_user, query).create(<%= params_method_name %>)
26
+
27
+ <%= resource_instance %> = <%= resource_name %>.result
28
+
29
+ if <%= resource_name %>.successful?
30
+ success("<%= resource_name %> creado de forma exitosa")
31
+
32
+ respond_with_lesli(
33
+ turbo: stream_redirection(<%= resource_name %>_path(<%= resource_instance %>.id))
34
+ )
35
+ else
36
+ respond_with_lesli(
37
+ turbo: <%= resource_name %>.errors_as_sentence
38
+ )
39
+ end
40
+ end
41
+
42
+ def update
43
+ if <%= resource_instance %>.update(<%= params_method_name %>)
44
+ respond_with_lesli(
45
+ turbo: stream_notification_success("<%= resource_class_name %> updated successfully")
46
+ )
47
+ else
48
+ respond_with_lesli(
49
+ turbo: stream_notification_danger(<%= resource_instance %>.errors)
50
+ )
51
+ end
52
+ end
53
+
54
+ def destroy
55
+ return respond_with_not_found unless <%= resource_instance %>
56
+ return respond_with_unauthorized unless <%= resource_instance %>.is_editable_by?(current_user)
57
+
58
+ <%= resource_name %>_destroy_response = <%= service_class_name %>.destroy(current_user, <%= resource_instance %>)
59
+
60
+ if <%= resource_name %>_destroy_response.successful?
61
+ respond_with_successful
62
+ else
63
+ respond_with_error(<%= resource_name %>_destroy_response.payload.errors.full_messages.to_sentence)
64
+ end
65
+ end
66
+
67
+ private
68
+
69
+ def <%= set_resource_method_name %>
70
+ <%= resource_instance %> = <%= service_class_name %>.new(current_user, query).find(id: params[:id])
71
+ return respond_with_not_found unless <%= resource_instance %>.found?
72
+ end
73
+
74
+ def <%= params_method_name %>
75
+ params.require(:<%= resource_name %>).permit(
76
+ <% if permitted_attributes.any? -%>
77
+ <% permitted_attributes.each_with_index do |attribute, index| -%>
78
+ :<%= attribute %><%= "," unless index == permitted_attributes.length - 1 %>
79
+ <% end -%>
80
+ <% else -%>
81
+ # Add permitted attributes here
82
+ <% end -%>
83
+ )
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/generators"
4
+ require_relative "../base_generator"
5
+
6
+ module Lesli
7
+ module Generators
8
+ # Generates a Lesli-style model inside the current engine.
9
+ #
10
+ # Example:
11
+ # rails generate lesli:model tickets
12
+ #
13
+ # Result:
14
+ # app/models/lesli_support/ticket.rb
15
+ class ModelGenerator < BaseGenerator
16
+ argument :attributes, type: :array, default: [], banner: "field:type field:type"
17
+
18
+ source_root File.expand_path("templates", __dir__)
19
+
20
+ # Creates the model file from the template.
21
+ def create_model_file
22
+ template "model.rb.tt", model_file_path
23
+ end
24
+
25
+ private
26
+
27
+ # Returns the directory where the model file should be created.
28
+ #
29
+ # Example:
30
+ # app/models/lesli_support
31
+ def model_directory
32
+ File.join(ENGINE_ROOT, "app/models", engine_name)
33
+ end
34
+
35
+ # Returns the final path of the generated model file.
36
+ #
37
+ # Example:
38
+ # app/models/lesli_support/ticket.rb
39
+ def model_file_path
40
+ File.join(model_directory, "#{resource_name}.rb")
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module <%= engine_namespace %>
4
+ class <%= resource_class_name %> < ApplicationRecord
5
+ belongs_to :account
6
+
7
+ # Optional user relations
8
+ # belongs_to :owner, class_name: "Lesli::User"
9
+ # belongs_to :user, class_name: "Lesli::User"
10
+
11
+ # Optional item concerns
12
+ # include Lesli::Item::Tasks
13
+ # include Lesli::Item::Activities
14
+ # include Lesli::Item::Discussions
15
+ end
16
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/generators"
4
+ require_relative "../base_generator"
5
+
6
+ module Lesli
7
+ module Generators
8
+ # Main Lesli scaffold generator.
9
+ #
10
+ # This generator delegates work to the specialized generators.
11
+ class ScaffoldGenerator < BaseGenerator
12
+ argument :attributes, type: :array, default: [], banner: "field:type field:type"
13
+
14
+ def invoke_model_generator
15
+ invoke "lesli:model", [name, *attributes]
16
+ end
17
+
18
+ # Invokes the custom Lesli controller generator.
19
+ def invoke_controller_generator
20
+ invoke "lesli:controller", [name, *attributes]
21
+ end
22
+
23
+ # Invokes the custom Lesli service generator.
24
+ def invoke_service_generator
25
+ invoke "lesli:service", [name, *attributes]
26
+ end
27
+
28
+ def invoke_views_generator
29
+ invoke "lesli:views", [name, *attributes]
30
+ end
31
+
32
+ def invoke_migration_generator
33
+ invoke "active_record:migration", [migration_name, *attributes]
34
+ end
35
+
36
+ def invoke_route_generator
37
+ invoke "resource_route", [resource_collection_name]
38
+ end
39
+
40
+ private
41
+
42
+ def migration_name
43
+ "create_#{engine_name}_#{resource_collection_name}"
44
+ end
45
+ end
46
+ end
47
+ end