inertia_rails 3.4.0 → 3.6.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 (205) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +22 -0
  3. data/README.md +17 -13
  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 +4 -1
  178. data/lib/inertia_rails/controller.rb +16 -4
  179. data/lib/inertia_rails/defer_prop.rb +21 -0
  180. data/lib/inertia_rails/generators/controller_template_base.rb +63 -0
  181. data/lib/inertia_rails/generators/helper.rb +139 -0
  182. data/lib/inertia_rails/generators/scaffold_template_base.rb +45 -0
  183. data/lib/inertia_rails/ignore_on_first_load_prop.rb +6 -0
  184. data/lib/inertia_rails/inertia_rails.rb +34 -12
  185. data/lib/inertia_rails/lazy_prop.rb +24 -0
  186. data/lib/inertia_rails/merge_prop.rb +14 -0
  187. data/lib/inertia_rails/middleware.rb +7 -2
  188. data/lib/inertia_rails/optional_prop.rb +6 -0
  189. data/lib/inertia_rails/renderer.rb +106 -20
  190. data/lib/inertia_rails/version.rb +1 -1
  191. data/lib/inertia_rails.rb +2 -0
  192. data/lib/patches/better_errors.rb +10 -8
  193. data/lib/patches/debug_exceptions/patch-5-0.rb +7 -3
  194. data/lib/patches/debug_exceptions/patch-5-1.rb +7 -3
  195. data/lib/patches/mapper.rb +9 -5
  196. data/lib/patches/request.rb +10 -6
  197. metadata +185 -13
  198. data/lib/generators/inertia_rails/install/react/InertiaExample.jsx +0 -9
  199. data/lib/generators/inertia_rails/install/react/inertia.jsx +0 -17
  200. data/lib/generators/inertia_rails/install/svelte/InertiaExample.svelte +0 -11
  201. data/lib/generators/inertia_rails/install/svelte/inertia.js +0 -14
  202. data/lib/generators/inertia_rails/install/vue/InertiaExample.vue +0 -11
  203. data/lib/generators/inertia_rails/install/vue/inertia.js +0 -20
  204. data/lib/generators/inertia_rails/install_generator.rb +0 -84
  205. 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
@@ -16,6 +16,9 @@ module InertiaRails
16
16
  # controller configuration.
17
17
  layout: true,
18
18
 
19
+ # Whether to encrypt the history state in the client.
20
+ encrypt_history: false,
21
+
19
22
  # SSR options.
20
23
  ssr_enabled: false,
21
24
  ssr_url: 'http://localhost:13714',
@@ -63,7 +66,7 @@ module InertiaRails
63
66
  end
64
67
 
65
68
  def component_path_resolver(path:, action:)
66
- @options[:component_path_resolver].call(path:, action:)
69
+ @options[:component_path_resolver].call(path: path, action: action)
67
70
  end
68
71
 
69
72
  OPTION_NAMES.each do |option|
@@ -123,7 +123,7 @@ module InertiaRails
123
123
  end
124
124
 
125
125
  def redirect_to(options = {}, response_options = {})
126
- capture_inertia_errors(response_options)
126
+ capture_inertia_session_options(response_options)
127
127
  super
128
128
  end
129
129
 
@@ -155,10 +155,22 @@ module InertiaRails
155
155
  head :conflict
156
156
  end
157
157
 
158
- def capture_inertia_errors(options)
159
- if (inertia_errors = options.dig(:inertia, :errors))
160
- session[:inertia_errors] = inertia_errors.to_hash
158
+ def capture_inertia_session_options(options)
159
+ return unless (inertia = options[:inertia])
160
+
161
+ if (inertia_errors = inertia[:errors])
162
+ if inertia_errors.respond_to?(:to_hash)
163
+ session[:inertia_errors] = inertia_errors.to_hash
164
+ else
165
+ InertiaRails.deprecator.warn(
166
+ "Object passed to `inertia: { errors: ... }` must respond to `to_hash`. Pass a hash-like object instead."
167
+ )
168
+ session[:inertia_errors] = inertia_errors
169
+ end
170
+
161
171
  end
172
+
173
+ session[:inertia_clear_history] = inertia[:clear_history] if inertia[:clear_history]
162
174
  end
163
175
  end
164
176
  end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module InertiaRails
4
+ class DeferProp < IgnoreOnFirstLoadProp
5
+ DEFAULT_GROUP = 'default'
6
+
7
+ attr_reader :group
8
+
9
+ def initialize(group: nil, merge: nil, &block)
10
+ super(&block)
11
+
12
+ @group = group || DEFAULT_GROUP
13
+ @merge = merge
14
+ @block = block
15
+ end
16
+
17
+ def merge?
18
+ @merge
19
+ end
20
+ end
21
+ 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
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module InertiaRails
4
+ class IgnoreOnFirstLoadProp < BaseProp
5
+ end
6
+ end