inertia_rails 3.4.0 → 3.5.0

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 (199) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +11 -0
  3. data/README.md +6 -7
  4. data/lib/generators/inertia/controller/controller_generator.rb +18 -0
  5. data/lib/generators/inertia/controller/templates/controller.rb.tt +10 -0
  6. data/lib/generators/inertia/install/frameworks.yml +98 -0
  7. data/lib/generators/inertia/install/helpers.rb +51 -0
  8. data/lib/generators/inertia/install/install_generator.rb +291 -0
  9. data/lib/generators/inertia/install/js_package_manager.rb +50 -0
  10. data/lib/generators/inertia/install/templates/assets/inertia.svg +1 -0
  11. data/lib/generators/inertia/install/templates/assets/react.svg +1 -0
  12. data/lib/generators/inertia/install/templates/assets/svelte.svg +1 -0
  13. data/lib/generators/inertia/install/templates/assets/vite_ruby.svg +1 -0
  14. data/lib/generators/inertia/install/templates/assets/vue.svg +1 -0
  15. data/lib/generators/{inertia_rails/install → inertia/install/templates}/controller.rb +3 -1
  16. data/lib/generators/inertia/install/templates/dev +23 -0
  17. data/lib/generators/inertia/install/templates/initializer.rb +6 -0
  18. data/lib/generators/inertia/install/templates/react/InertiaExample.jsx +60 -0
  19. data/lib/generators/inertia/install/templates/react/InertiaExample.module.css +80 -0
  20. data/lib/generators/inertia/install/templates/react/InertiaExample.tsx +60 -0
  21. data/lib/generators/inertia/install/templates/react/inertia.js +45 -0
  22. data/lib/generators/inertia/install/templates/react/inertia.ts +51 -0
  23. data/lib/generators/inertia/install/templates/react/tsconfig.app.json +27 -0
  24. data/lib/generators/inertia/install/templates/react/tsconfig.json +11 -0
  25. data/lib/generators/inertia/install/templates/react/tsconfig.node.json +13 -0
  26. data/lib/generators/inertia/install/templates/react/vite-env.d.ts +1 -0
  27. data/lib/generators/inertia/install/templates/svelte/InertiaExample.svelte +112 -0
  28. data/lib/generators/inertia/install/templates/svelte/InertiaExample.ts.svelte +112 -0
  29. data/lib/generators/inertia/install/templates/svelte/inertia.js +44 -0
  30. data/lib/generators/inertia/install/templates/svelte/inertia.ts.tt +45 -0
  31. data/lib/generators/inertia/install/templates/svelte/svelte.config.js +7 -0
  32. data/lib/generators/inertia/install/templates/svelte/tsconfig.json +21 -0
  33. data/lib/generators/inertia/install/templates/svelte/tsconfig.node.json +12 -0
  34. data/lib/generators/inertia/install/templates/svelte/vite-env.d.ts +2 -0
  35. data/lib/generators/inertia/install/templates/svelte4/InertiaExample.svelte +116 -0
  36. data/lib/generators/inertia/install/templates/svelte4/InertiaExample.ts.svelte +116 -0
  37. data/lib/generators/inertia/install/templates/svelte4/inertia.js +43 -0
  38. data/lib/generators/inertia/install/templates/svelte4/inertia.ts.tt +44 -0
  39. data/lib/generators/inertia/install/templates/svelte4/svelte.config.js +7 -0
  40. data/lib/generators/inertia/install/templates/svelte4/tsconfig.json +21 -0
  41. data/lib/generators/inertia/install/templates/svelte4/tsconfig.node.json +12 -0
  42. data/lib/generators/inertia/install/templates/svelte4/vite-env.d.ts +2 -0
  43. data/lib/generators/inertia/install/templates/tailwind/application.css +13 -0
  44. data/lib/generators/inertia/install/templates/tailwind/postcss.config.js +6 -0
  45. data/lib/generators/inertia/install/templates/tailwind/tailwind.config.js.tt +18 -0
  46. data/lib/generators/inertia/install/templates/vue/InertiaExample.ts.vue +117 -0
  47. data/lib/generators/inertia/install/templates/vue/InertiaExample.vue +117 -0
  48. data/lib/generators/inertia/install/templates/vue/inertia.js +35 -0
  49. data/lib/generators/inertia/install/templates/vue/inertia.ts +35 -0
  50. data/lib/generators/inertia/install/templates/vue/tsconfig.app.json +24 -0
  51. data/lib/generators/inertia/install/templates/vue/tsconfig.json +11 -0
  52. data/lib/generators/inertia/install/templates/vue/tsconfig.node.json +22 -0
  53. data/lib/generators/inertia/install/templates/vue/vite-env.d.ts +1 -0
  54. data/lib/generators/inertia/scaffold/scaffold_generator.rb +16 -0
  55. data/lib/generators/inertia/scaffold_controller/scaffold_controller_generator.rb +60 -0
  56. data/lib/generators/inertia/scaffold_controller/templates/controller.rb.tt +100 -0
  57. data/lib/generators/inertia_templates/controller/controller_generator.rb +12 -0
  58. data/lib/generators/inertia_templates/controller/templates/react/view.jsx.tt +8 -0
  59. data/lib/generators/inertia_templates/controller/templates/react/view.tsx.tt +8 -0
  60. data/lib/generators/inertia_templates/controller/templates/svelte/view.svelte.tt +2 -0
  61. data/lib/generators/inertia_templates/controller/templates/svelte4/view.svelte.tt +2 -0
  62. data/lib/generators/inertia_templates/controller/templates/vue/view.vue.tt +4 -0
  63. data/lib/generators/inertia_templates/scaffold/scaffold_generator.rb +12 -0
  64. data/lib/generators/inertia_templates/scaffold/templates/react/Edit.jsx.tt +35 -0
  65. data/lib/generators/inertia_templates/scaffold/templates/react/Edit.tsx.tt +40 -0
  66. data/lib/generators/inertia_templates/scaffold/templates/react/Form.jsx.tt +111 -0
  67. data/lib/generators/inertia_templates/scaffold/templates/react/Form.tsx.tt +130 -0
  68. data/lib/generators/inertia_templates/scaffold/templates/react/Index.jsx.tt +26 -0
  69. data/lib/generators/inertia_templates/scaffold/templates/react/Index.tsx.tt +32 -0
  70. data/lib/generators/inertia_templates/scaffold/templates/react/New.jsx.tt +27 -0
  71. data/lib/generators/inertia_templates/scaffold/templates/react/New.tsx.tt +32 -0
  72. data/lib/generators/inertia_templates/scaffold/templates/react/One.jsx.tt +26 -0
  73. data/lib/generators/inertia_templates/scaffold/templates/react/One.tsx.tt +32 -0
  74. data/lib/generators/inertia_templates/scaffold/templates/react/Show.jsx.tt +32 -0
  75. data/lib/generators/inertia_templates/scaffold/templates/react/Show.tsx.tt +38 -0
  76. data/lib/generators/inertia_templates/scaffold/templates/react/types.ts.tt +19 -0
  77. data/lib/generators/inertia_templates/scaffold/templates/svelte/Edit.svelte.tt +36 -0
  78. data/lib/generators/inertia_templates/scaffold/templates/svelte/Edit.ts.svelte.tt +37 -0
  79. data/lib/generators/inertia_templates/scaffold/templates/svelte/Form.svelte.tt +97 -0
  80. data/lib/generators/inertia_templates/scaffold/templates/svelte/Form.ts.svelte.tt +102 -0
  81. data/lib/generators/inertia_templates/scaffold/templates/svelte/Index.svelte.tt +35 -0
  82. data/lib/generators/inertia_templates/scaffold/templates/svelte/Index.ts.svelte.tt +39 -0
  83. data/lib/generators/inertia_templates/scaffold/templates/svelte/New.svelte.tt +29 -0
  84. data/lib/generators/inertia_templates/scaffold/templates/svelte/New.ts.svelte.tt +30 -0
  85. data/lib/generators/inertia_templates/scaffold/templates/svelte/One.svelte.tt +28 -0
  86. data/lib/generators/inertia_templates/scaffold/templates/svelte/One.ts.svelte.tt +30 -0
  87. data/lib/generators/inertia_templates/scaffold/templates/svelte/Show.svelte.tt +35 -0
  88. data/lib/generators/inertia_templates/scaffold/templates/svelte/Show.ts.svelte.tt +39 -0
  89. data/lib/generators/inertia_templates/scaffold/templates/svelte/types.ts.tt +19 -0
  90. data/lib/generators/inertia_templates/scaffold/templates/svelte4/Edit.svelte.tt +37 -0
  91. data/lib/generators/inertia_templates/scaffold/templates/svelte4/Edit.ts.svelte.tt +38 -0
  92. data/lib/generators/inertia_templates/scaffold/templates/svelte4/Form.svelte.tt +96 -0
  93. data/lib/generators/inertia_templates/scaffold/templates/svelte4/Form.ts.svelte.tt +106 -0
  94. data/lib/generators/inertia_templates/scaffold/templates/svelte4/Index.svelte.tt +36 -0
  95. data/lib/generators/inertia_templates/scaffold/templates/svelte4/Index.ts.svelte.tt +37 -0
  96. data/lib/generators/inertia_templates/scaffold/templates/svelte4/New.svelte.tt +30 -0
  97. data/lib/generators/inertia_templates/scaffold/templates/svelte4/New.ts.svelte.tt +31 -0
  98. data/lib/generators/inertia_templates/scaffold/templates/svelte4/One.svelte.tt +28 -0
  99. data/lib/generators/inertia_templates/scaffold/templates/svelte4/One.ts.svelte.tt +30 -0
  100. data/lib/generators/inertia_templates/scaffold/templates/svelte4/Show.svelte.tt +39 -0
  101. data/lib/generators/inertia_templates/scaffold/templates/svelte4/Show.ts.svelte.tt +40 -0
  102. data/lib/generators/inertia_templates/scaffold/templates/svelte4/types.ts.tt +19 -0
  103. data/lib/generators/inertia_templates/scaffold/templates/vue/Edit.ts.vue.tt +37 -0
  104. data/lib/generators/inertia_templates/scaffold/templates/vue/Edit.vue.tt +36 -0
  105. data/lib/generators/inertia_templates/scaffold/templates/vue/Form.ts.vue.tt +101 -0
  106. data/lib/generators/inertia_templates/scaffold/templates/vue/Form.vue.tt +94 -0
  107. data/lib/generators/inertia_templates/scaffold/templates/vue/Index.ts.vue.tt +35 -0
  108. data/lib/generators/inertia_templates/scaffold/templates/vue/Index.vue.tt +31 -0
  109. data/lib/generators/inertia_templates/scaffold/templates/vue/New.ts.vue.tt +30 -0
  110. data/lib/generators/inertia_templates/scaffold/templates/vue/New.vue.tt +29 -0
  111. data/lib/generators/inertia_templates/scaffold/templates/vue/One.ts.vue.tt +28 -0
  112. data/lib/generators/inertia_templates/scaffold/templates/vue/One.vue.tt +26 -0
  113. data/lib/generators/inertia_templates/scaffold/templates/vue/Show.ts.vue.tt +41 -0
  114. data/lib/generators/inertia_templates/scaffold/templates/vue/Show.vue.tt +37 -0
  115. data/lib/generators/inertia_templates/scaffold/templates/vue/types.ts.tt +19 -0
  116. data/lib/generators/inertia_tw_templates/controller/controller_generator.rb +12 -0
  117. data/lib/generators/inertia_tw_templates/controller/templates/react/view.jsx.tt +8 -0
  118. data/lib/generators/inertia_tw_templates/controller/templates/react/view.tsx.tt +8 -0
  119. data/lib/generators/inertia_tw_templates/controller/templates/svelte/view.svelte.tt +2 -0
  120. data/lib/generators/inertia_tw_templates/controller/templates/svelte4/view.svelte.tt +2 -0
  121. data/lib/generators/inertia_tw_templates/controller/templates/vue/view.vue.tt +4 -0
  122. data/lib/generators/inertia_tw_templates/scaffold/scaffold_generator.rb +12 -0
  123. data/lib/generators/inertia_tw_templates/scaffold/templates/react/Edit.jsx.tt +42 -0
  124. data/lib/generators/inertia_tw_templates/scaffold/templates/react/Edit.tsx.tt +47 -0
  125. data/lib/generators/inertia_tw_templates/scaffold/templates/react/Form.jsx.tt +122 -0
  126. data/lib/generators/inertia_tw_templates/scaffold/templates/react/Form.tsx.tt +142 -0
  127. data/lib/generators/inertia_tw_templates/scaffold/templates/react/Index.jsx.tt +43 -0
  128. data/lib/generators/inertia_tw_templates/scaffold/templates/react/Index.tsx.tt +49 -0
  129. data/lib/generators/inertia_tw_templates/scaffold/templates/react/New.jsx.tt +30 -0
  130. data/lib/generators/inertia_tw_templates/scaffold/templates/react/New.tsx.tt +35 -0
  131. data/lib/generators/inertia_tw_templates/scaffold/templates/react/One.jsx.tt +26 -0
  132. data/lib/generators/inertia_tw_templates/scaffold/templates/react/One.tsx.tt +32 -0
  133. data/lib/generators/inertia_tw_templates/scaffold/templates/react/Show.jsx.tt +47 -0
  134. data/lib/generators/inertia_tw_templates/scaffold/templates/react/Show.tsx.tt +53 -0
  135. data/lib/generators/inertia_tw_templates/scaffold/templates/react/types.ts.tt +19 -0
  136. data/lib/generators/inertia_tw_templates/scaffold/templates/svelte/Edit.svelte.tt +44 -0
  137. data/lib/generators/inertia_tw_templates/scaffold/templates/svelte/Edit.ts.svelte.tt +45 -0
  138. data/lib/generators/inertia_tw_templates/scaffold/templates/svelte/Form.svelte.tt +118 -0
  139. data/lib/generators/inertia_tw_templates/scaffold/templates/svelte/Form.ts.svelte.tt +123 -0
  140. data/lib/generators/inertia_tw_templates/scaffold/templates/svelte/Index.svelte.tt +42 -0
  141. data/lib/generators/inertia_tw_templates/scaffold/templates/svelte/Index.ts.svelte.tt +46 -0
  142. data/lib/generators/inertia_tw_templates/scaffold/templates/svelte/New.svelte.tt +32 -0
  143. data/lib/generators/inertia_tw_templates/scaffold/templates/svelte/New.ts.svelte.tt +33 -0
  144. data/lib/generators/inertia_tw_templates/scaffold/templates/svelte/One.svelte.tt +28 -0
  145. data/lib/generators/inertia_tw_templates/scaffold/templates/svelte/One.ts.svelte.tt +30 -0
  146. data/lib/generators/inertia_tw_templates/scaffold/templates/svelte/Show.svelte.tt +50 -0
  147. data/lib/generators/inertia_tw_templates/scaffold/templates/svelte/Show.ts.svelte.tt +54 -0
  148. data/lib/generators/inertia_tw_templates/scaffold/templates/svelte/types.ts.tt +19 -0
  149. data/lib/generators/inertia_tw_templates/scaffold/templates/svelte4/Edit.svelte.tt +45 -0
  150. data/lib/generators/inertia_tw_templates/scaffold/templates/svelte4/Edit.ts.svelte.tt +46 -0
  151. data/lib/generators/inertia_tw_templates/scaffold/templates/svelte4/Form.svelte.tt +120 -0
  152. data/lib/generators/inertia_tw_templates/scaffold/templates/svelte4/Form.ts.svelte.tt +130 -0
  153. data/lib/generators/inertia_tw_templates/scaffold/templates/svelte4/Index.svelte.tt +43 -0
  154. data/lib/generators/inertia_tw_templates/scaffold/templates/svelte4/Index.ts.svelte.tt +44 -0
  155. data/lib/generators/inertia_tw_templates/scaffold/templates/svelte4/New.svelte.tt +33 -0
  156. data/lib/generators/inertia_tw_templates/scaffold/templates/svelte4/New.ts.svelte.tt +34 -0
  157. data/lib/generators/inertia_tw_templates/scaffold/templates/svelte4/One.svelte.tt +28 -0
  158. data/lib/generators/inertia_tw_templates/scaffold/templates/svelte4/One.ts.svelte.tt +30 -0
  159. data/lib/generators/inertia_tw_templates/scaffold/templates/svelte4/Show.svelte.tt +51 -0
  160. data/lib/generators/inertia_tw_templates/scaffold/templates/svelte4/Show.ts.svelte.tt +52 -0
  161. data/lib/generators/inertia_tw_templates/scaffold/templates/svelte4/types.ts.tt +19 -0
  162. data/lib/generators/inertia_tw_templates/scaffold/templates/vue/Edit.ts.vue.tt +45 -0
  163. data/lib/generators/inertia_tw_templates/scaffold/templates/vue/Edit.vue.tt +44 -0
  164. data/lib/generators/inertia_tw_templates/scaffold/templates/vue/Form.ts.vue.tt +134 -0
  165. data/lib/generators/inertia_tw_templates/scaffold/templates/vue/Form.vue.tt +127 -0
  166. data/lib/generators/inertia_tw_templates/scaffold/templates/vue/Index.ts.vue.tt +47 -0
  167. data/lib/generators/inertia_tw_templates/scaffold/templates/vue/Index.vue.tt +43 -0
  168. data/lib/generators/inertia_tw_templates/scaffold/templates/vue/New.ts.vue.tt +33 -0
  169. data/lib/generators/inertia_tw_templates/scaffold/templates/vue/New.vue.tt +32 -0
  170. data/lib/generators/inertia_tw_templates/scaffold/templates/vue/One.ts.vue.tt +28 -0
  171. data/lib/generators/inertia_tw_templates/scaffold/templates/vue/One.vue.tt +26 -0
  172. data/lib/generators/inertia_tw_templates/scaffold/templates/vue/Show.ts.vue.tt +53 -0
  173. data/lib/generators/inertia_tw_templates/scaffold/templates/vue/Show.vue.tt +49 -0
  174. data/lib/generators/inertia_tw_templates/scaffold/templates/vue/types.ts.tt +19 -0
  175. data/lib/inertia_rails/always_prop.rb +6 -0
  176. data/lib/inertia_rails/base_prop.rb +14 -0
  177. data/lib/inertia_rails/configuration.rb +1 -1
  178. data/lib/inertia_rails/controller.rb +8 -1
  179. data/lib/inertia_rails/generators/controller_template_base.rb +63 -0
  180. data/lib/inertia_rails/generators/helper.rb +139 -0
  181. data/lib/inertia_rails/generators/scaffold_template_base.rb +45 -0
  182. data/lib/inertia_rails/inertia_rails.rb +18 -12
  183. data/lib/inertia_rails/lazy_prop.rb +20 -0
  184. data/lib/inertia_rails/renderer.rb +71 -17
  185. data/lib/inertia_rails/version.rb +1 -1
  186. data/lib/patches/better_errors.rb +10 -8
  187. data/lib/patches/debug_exceptions/patch-5-0.rb +7 -3
  188. data/lib/patches/debug_exceptions/patch-5-1.rb +7 -3
  189. data/lib/patches/mapper.rb +9 -5
  190. data/lib/patches/request.rb +10 -6
  191. metadata +181 -13
  192. data/lib/generators/inertia_rails/install/react/InertiaExample.jsx +0 -9
  193. data/lib/generators/inertia_rails/install/react/inertia.jsx +0 -17
  194. data/lib/generators/inertia_rails/install/svelte/InertiaExample.svelte +0 -11
  195. data/lib/generators/inertia_rails/install/svelte/inertia.js +0 -14
  196. data/lib/generators/inertia_rails/install/vue/InertiaExample.vue +0 -11
  197. data/lib/generators/inertia_rails/install/vue/inertia.js +0 -20
  198. data/lib/generators/inertia_rails/install_generator.rb +0 -84
  199. data/lib/inertia_rails/lazy.rb +0 -28
@@ -0,0 +1,43 @@
1
+ <template>
2
+ <Head title="<%= human_name.pluralize %>" />
3
+
4
+ <div className="mx-auto md:w-2/3 w-full px-8 pt-8">
5
+ <p
6
+ v-if="flash.notice"
7
+ class="py-2 px-3 bg-green-50 mb-5 text-green-500 font-medium rounded-lg inline-block"
8
+ >
9
+ {{ flash.notice }}
10
+ </p>
11
+
12
+ <div class="flex justify-between items-center">
13
+ <h1 class="font-bold text-4xl"><%= human_name.pluralize %></h1>
14
+ <Link
15
+ href="<%= js_new_resource_path %>"
16
+ class="rounded-lg py-3 px-5 bg-blue-600 text-white block font-medium"
17
+ >
18
+ New <%= human_name.downcase %>
19
+ </Link>
20
+ </div>
21
+
22
+ <div class="min-w-full">
23
+ <template v-for="<%= singular_table_name %> in <%= plural_table_name %>" :key="<%= singular_table_name %>.id">
24
+ <<%= inertia_component_name %> :<%= singular_table_name %>="<%= singular_table_name %>" />
25
+ <p>
26
+ <Link
27
+ :href="`<%= js_resource_path %>`"
28
+ class="ml-2 rounded-lg py-3 px-5 bg-gray-100 inline-block font-medium"
29
+ >
30
+ Show this <%= human_name.downcase %>
31
+ </Link>
32
+ </p>
33
+ </template>
34
+ </div>
35
+ </div>
36
+ </template>
37
+
38
+ <script setup>
39
+ import { Head, Link } from '@inertiajs/vue3'
40
+ import <%= inertia_component_name %> from './<%= inertia_component_name %>.vue'
41
+
42
+ const { <%= plural_table_name %>, flash } = defineProps(['<%= plural_table_name %>', 'flash'])
43
+ </script>
@@ -0,0 +1,33 @@
1
+ <template>
2
+ <Head title="New <%= human_name.downcase %>" />
3
+
4
+ <div className="mx-auto md:w-2/3 w-full px-8 pt-8">
5
+ <h1 class="font-bold text-4xl">New <%= human_name.downcase %></h1>
6
+
7
+ <Form
8
+ :<%= singular_table_name %>="<%= singular_table_name %>"
9
+ submitText="Create <%= human_name %>"
10
+ @onSubmit="handleSubmit"
11
+ />
12
+
13
+ <Link
14
+ href="<%= js_resources_path %>"
15
+ class="ml-2 rounded-lg py-3 px-5 bg-gray-100 inline-block font-medium"
16
+ >
17
+ Back to <%= human_name.pluralize.downcase %>
18
+ </Link>
19
+ </div>
20
+ </template>
21
+
22
+ <script setup lang="ts">
23
+ import { Head, InertiaForm, Link } from '@inertiajs/vue3'
24
+ import Form from './Form.vue'
25
+ import { <%= inertia_model_form_type %>, <%= inertia_model_type %> } from './types'
26
+
27
+ const { <%= singular_table_name %> } = defineProps<{ <%= singular_table_name %>: <%= inertia_model_type %> }>()
28
+
29
+ const handleSubmit = (form: InertiaForm<<%= inertia_model_form_type %>>) => {
30
+ form.transform((data) => ({ <%= singular_table_name %>: data }))
31
+ form.post('<%= js_resources_path %>')
32
+ }
33
+ </script>
@@ -0,0 +1,32 @@
1
+ <template>
2
+ <Head title="New <%= human_name.downcase %>" />
3
+
4
+ <div className="mx-auto md:w-2/3 w-full px-8 pt-8">
5
+ <h1 class="font-bold text-4xl">New <%= human_name.downcase %></h1>
6
+
7
+ <Form
8
+ :<%= singular_table_name %>="<%= singular_table_name %>"
9
+ submitText="Create <%= human_name %>"
10
+ @onSubmit="handleSubmit"
11
+ />
12
+
13
+ <Link
14
+ href="<%= js_resources_path %>"
15
+ class="ml-2 rounded-lg py-3 px-5 bg-gray-100 inline-block font-medium"
16
+ >
17
+ Back to <%= human_name.pluralize.downcase %>
18
+ </Link>
19
+ </div>
20
+ </template>
21
+
22
+ <script setup>
23
+ import { Head, Link } from '@inertiajs/vue3'
24
+ import Form from './Form.vue'
25
+
26
+ const { <%= singular_table_name %> } = defineProps(['<%= singular_table_name %>'])
27
+
28
+ const handleSubmit = (form) => {
29
+ form.transform((data) => ({ <%= singular_table_name %>: data }))
30
+ form.post('<%= js_resources_path %>')
31
+ }
32
+ </script>
@@ -0,0 +1,28 @@
1
+ <template>
2
+ <div>
3
+ <% attributes.reject(&:password_digest?).each do |attribute| -%>
4
+ <p class="my-5">
5
+ <strong class="block font-medium mb-1"><%= attribute.human_name %>:</strong>
6
+ <% if attribute.attachment? -%>
7
+ <a v-if="<%= singular_table_name %>.<%= attribute.column_name %>" :href="<%= singular_table_name %>.<%= attribute.column_name %>.url">
8
+ {{ <%= singular_table_name %>.<%= attribute.column_name %>.filename }}
9
+ </a>
10
+ </p>
11
+ <% elsif attribute.attachments? -%>
12
+ </p>
13
+ <div v-for="file in <%= singular_table_name %>.<%= attribute.column_name %>">
14
+ <a :href="file.url">{{ file.filename }}</a>
15
+ </div>
16
+ <% else -%>
17
+ {{ <%= singular_table_name %>.<%= attribute.column_name %> }}
18
+ </p>
19
+ <% end -%>
20
+ <% end -%>
21
+ </div>
22
+ </template>
23
+
24
+ <script setup lang="ts">
25
+ import { <%= inertia_model_type %> } from './types'
26
+
27
+ const { <%= singular_table_name %> } = defineProps<{ <%= singular_table_name %>: <%= inertia_model_type %> }>()
28
+ </script>
@@ -0,0 +1,26 @@
1
+ <template>
2
+ <div>
3
+ <% attributes.reject(&:password_digest?).each do |attribute| -%>
4
+ <p class="my-5">
5
+ <strong class="block font-medium mb-1"><%= attribute.human_name %>:</strong>
6
+ <% if attribute.attachment? -%>
7
+ <a v-if="<%= singular_table_name %>.<%= attribute.column_name %>" :href="<%= singular_table_name %>.<%= attribute.column_name %>.url">
8
+ {{ <%= singular_table_name %>.<%= attribute.column_name %>.filename }}
9
+ </a>
10
+ </p>
11
+ <% elsif attribute.attachments? -%>
12
+ </p>
13
+ <div v-for="file in <%= singular_table_name %>.<%= attribute.column_name %>">
14
+ <a :href="file.url">{{ file.filename }}</a>
15
+ </div>
16
+ <% else -%>
17
+ {{ <%= singular_table_name %>.<%= attribute.column_name %> }}
18
+ </p>
19
+ <% end -%>
20
+ <% end -%>
21
+ </div>
22
+ </template>
23
+
24
+ <script setup>
25
+ const { <%= singular_table_name %> } = defineProps(['<%= singular_table_name %>'])
26
+ </script>
@@ -0,0 +1,53 @@
1
+ <template>
2
+ <Head :title="`<%= human_name %> #${<%= singular_table_name %>.id}`" />
3
+
4
+ <div className="mx-auto md:w-2/3 w-full px-8 pt-8">
5
+ <div class="mx-auto">
6
+ <p
7
+ v-if="flash.notice"
8
+ class="py-2 px-3 bg-green-50 mb-5 text-green-500 font-medium rounded-lg inline-block"
9
+ >
10
+ {{ flash.notice }}
11
+ </p>
12
+
13
+ <h1 class="font-bold text-4xl"><%= human_name %> #{{ <%= singular_table_name %>.id }}</h1>
14
+
15
+ <<%= inertia_component_name %> :<%= singular_table_name %>="<%= singular_table_name %>" />
16
+
17
+ <Link
18
+ :href="`<%= js_edit_resource_path %>`"
19
+ class="ml-2 rounded-lg py-3 px-5 bg-gray-100 inline-block font-medium"
20
+ >
21
+ Edit this <%= human_name.downcase %>
22
+ </Link>
23
+ <Link
24
+ href="<%= js_resources_path %>"
25
+ class="ml-2 rounded-lg py-3 px-5 bg-gray-100 inline-block font-medium"
26
+ >
27
+ Back to <%= human_name.pluralize.downcase %>
28
+ </Link>
29
+
30
+ <div class="inline-block ml-2">
31
+ <Link
32
+ :href="`<%= js_resource_path %>`"
33
+ as="button"
34
+ method="delete"
35
+ class="mt-2 rounded-lg py-3 px-5 bg-gray-100 font-medium"
36
+ >
37
+ Destroy this <%= human_name.downcase %>
38
+ </Link>
39
+ </div>
40
+ </div>
41
+ </div>
42
+ </template>
43
+
44
+ <script setup lang="ts">
45
+ import { Head, Link } from '@inertiajs/vue3'
46
+ import <%= inertia_component_name %> from './<%= inertia_component_name %>.vue'
47
+ import { <%= inertia_model_type %> } from './types'
48
+
49
+ const { <%= singular_table_name %>, flash } = defineProps<{
50
+ <%= singular_table_name %>: <%= inertia_model_type %>
51
+ flash: { notice?: string }
52
+ }>()
53
+ </script>
@@ -0,0 +1,49 @@
1
+ <template>
2
+ <Head :title="`<%= human_name %> #${<%= singular_table_name %>.id}`" />
3
+
4
+ <div className="mx-auto md:w-2/3 w-full px-8 pt-8">
5
+ <div class="mx-auto">
6
+ <p
7
+ v-if="flash.notice"
8
+ class="py-2 px-3 bg-green-50 mb-5 text-green-500 font-medium rounded-lg inline-block"
9
+ >
10
+ {{ flash.notice }}
11
+ </p>
12
+
13
+ <h1 class="font-bold text-4xl"><%= human_name %> #{{ <%= singular_table_name %>.id }}</h1>
14
+
15
+ <<%= inertia_component_name %> :<%= singular_table_name %>="<%= singular_table_name %>" />
16
+
17
+ <Link
18
+ :href="`<%= js_edit_resource_path %>`"
19
+ class="ml-2 rounded-lg py-3 px-5 bg-gray-100 inline-block font-medium"
20
+ >
21
+ Edit this <%= human_name.downcase %>
22
+ </Link>
23
+ <Link
24
+ href="<%= js_resources_path %>"
25
+ class="ml-2 rounded-lg py-3 px-5 bg-gray-100 inline-block font-medium"
26
+ >
27
+ Back to <%= human_name.pluralize.downcase %>
28
+ </Link>
29
+
30
+ <div class="inline-block ml-2">
31
+ <Link
32
+ :href="`<%= js_resource_path %>`"
33
+ as="button"
34
+ method="delete"
35
+ class="mt-2 rounded-lg py-3 px-5 bg-gray-100 font-medium"
36
+ >
37
+ Destroy this <%= human_name.downcase %>
38
+ </Link>
39
+ </div>
40
+ </div>
41
+ </div>
42
+ </template>
43
+
44
+ <script setup>
45
+ import { Head, Link } from '@inertiajs/vue3'
46
+ import <%= inertia_component_name %> from './<%= inertia_component_name %>.vue'
47
+
48
+ const { <%= singular_table_name %>, flash } = defineProps(['<%= singular_table_name %>', 'flash'])
49
+ </script>
@@ -0,0 +1,19 @@
1
+ export interface <%= inertia_model_type %> {
2
+ id: number
3
+ <% attributes.reject(&:password_digest?).each do |attribute| -%>
4
+ <%= attribute.column_name %>: <%= ts_type(attribute) %>
5
+ <% end -%>
6
+ }
7
+
8
+ export type <%= inertia_model_form_type %> = Omit<<%= inertia_model_type %>, <%= omit_input_attributes.map { |a| "'#{a}'" }.join(' | ') %>><% if custom_form_attributes.any? -%> & {
9
+ <% custom_form_attributes.map do |attribute| -%>
10
+ <% if attribute.password_digest? -%>
11
+ password: string
12
+ password_confirmation: string
13
+ <% elsif attribute.attachment? -%>
14
+ <%= attribute.column_name %>?: File
15
+ <% elsif attribute.attachments? -%>
16
+ <%= attribute.column_name %>?: File[]
17
+ <% end -%>
18
+ <% end -%>
19
+ }<% end %>
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module InertiaRails
4
+ class AlwaysProp < BaseProp
5
+ end
6
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module InertiaRails
4
+ # Base class for all props.
5
+ class BaseProp
6
+ def initialize(&block)
7
+ @block = block
8
+ end
9
+
10
+ def call(controller)
11
+ controller.instance_exec(&@block)
12
+ end
13
+ end
14
+ end
@@ -63,7 +63,7 @@ module InertiaRails
63
63
  end
64
64
 
65
65
  def component_path_resolver(path:, action:)
66
- @options[:component_path_resolver].call(path:, action:)
66
+ @options[:component_path_resolver].call(path: path, action: action)
67
67
  end
68
68
 
69
69
  OPTION_NAMES.each do |option|
@@ -157,7 +157,14 @@ module InertiaRails
157
157
 
158
158
  def capture_inertia_errors(options)
159
159
  if (inertia_errors = options.dig(:inertia, :errors))
160
- session[:inertia_errors] = inertia_errors.to_hash
160
+ if inertia_errors.respond_to?(:to_hash)
161
+ session[:inertia_errors] = inertia_errors.to_hash
162
+ else
163
+ InertiaRails.deprecator.warn(
164
+ "Object passed to `inertia: { errors: ... }` must respond to `to_hash`. Pass a hash-like object instead."
165
+ )
166
+ session[:inertia_errors] = inertia_errors
167
+ end
161
168
  end
162
169
  end
163
170
  end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails/generators/named_base'
4
+ require 'inertia_rails/generators/helper'
5
+
6
+ module InertiaRails
7
+ module Generators
8
+ class ControllerTemplateBase < Rails::Generators::NamedBase
9
+ include Helper
10
+ class_option :frontend_framework, required: true, desc: 'Frontend framework to generate the views for.',
11
+ default: Helper.guess_the_default_framework
12
+
13
+ class_option :typescript, type: :boolean, desc: 'Whether to use TypeScript',
14
+ default: Helper.guess_typescript
15
+
16
+ argument :actions, type: :array, default: [], banner: 'action action'
17
+
18
+ def empty_views_dir
19
+ empty_directory base_path
20
+ end
21
+
22
+ def copy_view_files
23
+ actions.each do |action|
24
+ @action = action
25
+ @path = File.join(base_path, "#{action.camelize}.#{extension}")
26
+ template "#{options.frontend_framework}/#{template_filename}.#{extension}", @path
27
+ end
28
+ end
29
+
30
+ private
31
+
32
+ def base_path
33
+ File.join(pages_path, inertia_base_path)
34
+ end
35
+
36
+ def template_filename
37
+ 'view'
38
+ end
39
+
40
+ def pages_path
41
+ "#{root_path}/pages"
42
+ end
43
+
44
+ def root_path
45
+ (defined?(ViteRuby) ? ViteRuby.config.source_code_dir : 'app/frontend')
46
+ end
47
+
48
+ def extension
49
+ case options.frontend_framework
50
+ when 'react' then typescript? ? 'tsx' : 'jsx'
51
+ when 'vue' then 'vue'
52
+ when 'svelte', 'svelte4' then 'svelte'
53
+ else
54
+ raise ArgumentError, "Unknown frontend framework: #{options.frontend_framework}"
55
+ end
56
+ end
57
+
58
+ def typescript?
59
+ options.typescript
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,139 @@
1
+ # frozen_string_literal: true
2
+
3
+ module InertiaRails
4
+ module Generators
5
+ module Helper
6
+ class << self
7
+ def guess_the_default_framework
8
+ package = Rails.root.join('package.json').read
9
+ case package
10
+ when %r{@inertiajs/react}
11
+ 'react'
12
+ when %r{@inertiajs/svelte}
13
+ package.match?(/"svelte": "\^5/) ? 'svelte' : 'svelte4'
14
+ when %r{@inertiajs/vue3}
15
+ 'vue'
16
+ else
17
+ Thor::Shell::Basic.new.say_error 'Could not determine the Inertia.js framework you are using.'
18
+ exit 1
19
+ end
20
+ end
21
+
22
+ def guess_typescript
23
+ Rails.root.join('tsconfig.json').exist?
24
+ end
25
+
26
+ def guess_inertia_template
27
+ if Rails.root.join('tailwind.config.js').exist? || Rails.root.join('tailwind.config.ts').exist?
28
+ 'inertia_tw_templates'
29
+ else
30
+ 'inertia_templates'
31
+ end
32
+ end
33
+ end
34
+
35
+ def inertia_base_path
36
+ (class_path + [file_name]).map(&:camelize).join('/')
37
+ end
38
+
39
+ def inertia_component_name
40
+ singular_name.camelize
41
+ end
42
+
43
+ def inertia_model_type
44
+ "#{inertia_component_name}Type"
45
+ end
46
+
47
+ def inertia_model_form_type
48
+ "#{inertia_component_name}FormType"
49
+ end
50
+
51
+ def attributes_to_serialize
52
+ [:id] + attributes.reject do |attribute|
53
+ attribute.password_digest? ||
54
+ attribute.attachment? ||
55
+ attribute.attachments?
56
+ end.map(&:column_name)
57
+ end
58
+
59
+ def custom_form_attributes
60
+ attributes.select do |attribute|
61
+ attribute.password_digest? ||
62
+ attribute.attachment? ||
63
+ attribute.attachments?
64
+ end
65
+ end
66
+
67
+ def omit_input_attributes
68
+ ['id'] + attributes.select { |attribute| attribute.attachment? || attribute.attachments? }.map(&:column_name)
69
+ end
70
+
71
+ def js_resource_path
72
+ "#{route_url}/${#{singular_table_name}.id}"
73
+ end
74
+
75
+ def js_edit_resource_path
76
+ "#{route_url}/${#{singular_table_name}.id}/edit"
77
+ end
78
+
79
+ def js_new_resource_path
80
+ "#{route_url}/new"
81
+ end
82
+
83
+ def js_resources_path
84
+ route_url
85
+ end
86
+
87
+ def inertia_js_version
88
+ @inertia_js_version ||= Gem::Version.new(
89
+ JSON.parse(`npm ls @inertiajs/core --json`).then do |json|
90
+ json['dependencies'].values.first['version']
91
+ end
92
+ )
93
+ end
94
+
95
+ def ts_type(attribute)
96
+ case attribute.type
97
+ when :float, :decimal, :integer
98
+ 'number'
99
+ when :boolean
100
+ 'boolean'
101
+ when :attachment
102
+ '{ filename: string; url: string }'
103
+ when :attachments
104
+ '{ filename: string; url: string }[]'
105
+ else
106
+ 'string'
107
+ end
108
+ end
109
+
110
+ def input_type(attribute)
111
+ case attribute.type
112
+ when :text, :rich_text
113
+ 'text_area'
114
+ when :integer, :float, :decimal
115
+ 'number'
116
+ when :datetime, :timestamp, :time
117
+ 'datetime-local'
118
+ when :date
119
+ 'date'
120
+ when :boolean
121
+ 'checkbox'
122
+ when :attachments, :attachment
123
+ 'file'
124
+ else
125
+ 'text'
126
+ end
127
+ end
128
+
129
+ def default_value(attribute)
130
+ case attribute.type
131
+ when :boolean
132
+ 'false'
133
+ else
134
+ "''"
135
+ end
136
+ end
137
+ end
138
+ end
139
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails/generators/resource_helpers'
4
+ require_relative 'controller_template_base'
5
+
6
+ module InertiaRails
7
+ module Generators
8
+ class ScaffoldTemplateBase < ControllerTemplateBase
9
+ include Rails::Generators::ResourceHelpers
10
+
11
+ remove_argument :actions
12
+
13
+ argument :attributes, type: :array, default: [], banner: 'field:type field:type'
14
+
15
+ def copy_view_files
16
+ available_views.each do |view|
17
+ template "#{options.frontend_framework}/#{view}.#{template_extension}",
18
+ File.join(base_path, "#{view}.#{extension}")
19
+ end
20
+
21
+ template "#{options.frontend_framework}/#{partial_name}.#{template_extension}",
22
+ File.join(base_path, "#{inertia_component_name}.#{extension}")
23
+
24
+ template "#{options.frontend_framework}/types.ts", File.join(base_path, 'types.ts') if typescript?
25
+ end
26
+
27
+ private
28
+
29
+ def template_extension
30
+ return extension unless typescript?
31
+ return 'tsx' if options.frontend_framework == 'react'
32
+
33
+ "ts.#{extension}"
34
+ end
35
+
36
+ def available_views
37
+ %w[Index Edit Show New Form]
38
+ end
39
+
40
+ def partial_name
41
+ 'One'
42
+ end
43
+ end
44
+ end
45
+ end
@@ -1,20 +1,26 @@
1
- # Needed for `thread_mattr_accessor`
2
- require 'active_support/core_ext/module/attribute_accessors_per_thread'
3
- require 'inertia_rails/lazy'
1
+ require 'inertia_rails/base_prop'
2
+ require 'inertia_rails/always_prop'
3
+ require 'inertia_rails/lazy_prop'
4
4
  require 'inertia_rails/configuration'
5
5
 
6
6
  module InertiaRails
7
- CONFIGURATION = Configuration.default
7
+ class << self
8
+ CONFIGURATION = Configuration.default
8
9
 
9
- def self.configure
10
- yield(CONFIGURATION)
11
- end
10
+ def configure
11
+ yield(CONFIGURATION)
12
+ end
12
13
 
13
- def self.configuration
14
- CONFIGURATION
15
- end
14
+ def configuration
15
+ CONFIGURATION
16
+ end
17
+
18
+ def lazy(value = nil, &block)
19
+ LazyProp.new(value, &block)
20
+ end
16
21
 
17
- def self.lazy(value = nil, &block)
18
- InertiaRails::Lazy.new(value, &block)
22
+ def always(&block)
23
+ AlwaysProp.new(&block)
24
+ end
19
25
  end
20
26
  end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module InertiaRails
4
+ class LazyProp < BaseProp
5
+ def initialize(value = nil, &block)
6
+ raise ArgumentError, 'You must provide either a value or a block, not both' if value && block
7
+
8
+ @value = value
9
+ @block = block
10
+ end
11
+
12
+ def call(controller)
13
+ value.respond_to?(:call) ? controller.instance_exec(&value) : value
14
+ end
15
+
16
+ def value
17
+ @value.nil? ? @block : @value
18
+ end
19
+ end
20
+ end