uni_rails 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 32de6ce8c47b9fc788b686f9ccd709341c543f3e8f97b93383980b8814ff941e
4
- data.tar.gz: 52f9a0d16c28d7e5f3a326cd58fccea70687eb7fef1560d6e0dbf8c700fe61b4
3
+ metadata.gz: 3dbb41ea67dff2755cb5b77eae07f174a95bf99de2cf03a084739213c99033c9
4
+ data.tar.gz: 5c9414944b4616651a429657025c58444f330ceea500f164a92a8d7afcefc824
5
5
  SHA512:
6
- metadata.gz: 3695f3707ec840bc876d891da128bc3ab385b0327915ac5d714ae4b0e1cfc2f083b939fd9c8ab7199b85a9db0b8678627c67f1d8ced5ebf19142f19973a49ced
7
- data.tar.gz: ae3b6b9530ade148bca88cc8329dc3e71aca7f24829330ae9ac55c641710ed4551e2ca9e4b5532886fad5b285f1dd7dc2181cce9ced90a30051eec1dd3a4f7ce
6
+ metadata.gz: 980ece2224b2c31320c749eb07676912f27bf5285d6dcefcacae4196f15061140185cb8b51a565d4605db0fd95a669ec543b1750fcdeb024fab4cc7d5a61d93a
7
+ data.tar.gz: 49e8aa1ff7ec06d23cfa5a07d8d9546e036fe6255c71f6766faa42416631d0fdaf9d572333ebd066f6265e693f731586f77e19f3858f929f351cd82f28c4ff99
data/README.md CHANGED
@@ -1,18 +1,21 @@
1
1
  # UniRails
2
2
 
3
- UniRails is designed to streamline the process of creating Ruby on Rails applications within a single Ruby file. This approach is ideal for small personal CRUD (Create, Read, Update, Delete) applications or educational purposes, offering a simplified method for demonstrating Rails concepts.
3
+ UniRails makes it easy to build Ruby on Rails apps all within one Ruby file. It's perfect for small personal projects or teaching, as everything is one scroll away.
4
4
 
5
- Our goal is to facilitate educators and writers in crafting concise, illustrative examples for articles or books. Traditional Rails applications require a complex structure even for demonstrating basic concepts, which can be cumbersome and unnecessary. Our library addresses this issue by enabling the quick replication of a Ruby file to instantiate a fully operational Rails app, consolidating all essential components into one file.
5
+ We aim to help educators and writers create clear examples for articles or books. Rails requires a full folder structure to show the basics, which can be a hassle. UniRails cuts through that by letting you spin up a complete Rails app from just one Ruby file everything you need in one place.
6
6
 
7
- Embrace the convenience of single-file Rails applications with our library, where simplicity meets functionality.
7
+ Check out our [examples](/examples) to understand how the library creates Rails apps from a single file.
8
8
 
9
9
  ## Installation & Usage
10
10
 
11
11
  See some examples of how the UniRails library can be used
12
12
 
13
- - [json api](/examples/json_api.rb)
14
- - [todo app](/examples/todos.rb)
15
- - [hotwire](/examples/hotwire.rb)
13
+ - [Hello world](/examples/hello-world.rb)
14
+ - [Todos app (JSON API)](/examples/todos-api.rb)
15
+ - [Todos app (Rails scaffold)](/examples/todos-scaffold.rb) based off `bin/rails g scaffold todo name completed_at:datetime`
16
+ - [Todos app (Hotwire)](/examples/todos-hotwire.rb) based off online article: [turbo-rails-101-todo-list](https://www.colby.so/posts/turbo-rails-101-todo-list) by David Colby
17
+ - [App using Puma server](/examples/server-puma-app.rb)
18
+ - [App using Falcon server](/examples/server-falcon-app.rb)
16
19
 
17
20
  ## Development
18
21
 
@@ -30,7 +33,7 @@ We would like to support all railties and engines. Please help us support more o
30
33
 
31
34
  - [X] action_controller
32
35
  - [X] active_record
33
- - [ ] active_model/railtie
36
+ - [X] active_model/railtie
34
37
  - [ ] active_job/railtie
35
38
  - [ ] active_storage/engine
36
39
  - [ ] action_mailer/railtie
@@ -0,0 +1,25 @@
1
+ # Run the application
2
+ # $ ruby hello-world.rb
3
+
4
+ ENV['SECRET_KEY_BASE'] = 'my_secret_key_base'
5
+
6
+ require "bundler/inline"
7
+
8
+ gemfile(true) do
9
+ source "https://rubygems.org"
10
+ gem 'uni_rails'
11
+ end
12
+
13
+ require 'uni_rails'
14
+
15
+ UniRails::App.routes.append do
16
+ root 'pages#index'
17
+ end
18
+
19
+ class PagesController < ActionController::Base
20
+ def index
21
+ render plain: 'Hello world'
22
+ end
23
+ end
24
+
25
+ UniRails.run(Port: 3000)
@@ -0,0 +1,30 @@
1
+ # Run the application
2
+ # $ ruby server-falcon-app.rb
3
+
4
+ ENV['SECRET_KEY_BASE'] = 'my_secret_key_base'
5
+
6
+ require "bundler/inline"
7
+
8
+ gemfile(true) do
9
+ source "https://rubygems.org"
10
+
11
+ gem 'uni_rails'
12
+ gem 'falcon'
13
+ end
14
+
15
+ require 'uni_rails'
16
+ require 'rackup/handler/falcon'
17
+
18
+ UniRails.rackup_handler = Rackup::Handler::Falcon
19
+
20
+ UniRails::App.routes.append do
21
+ root 'pages#index'
22
+ end
23
+
24
+ class PagesController < ActionController::Base
25
+ def index
26
+ render plain: 'Application served by Falcon'
27
+ end
28
+ end
29
+
30
+ UniRails.run(Port: 3000)
@@ -0,0 +1,30 @@
1
+ # Run the application
2
+ # $ ruby server-puma-app.rb
3
+
4
+ ENV['SECRET_KEY_BASE'] = 'my_secret_key_base'
5
+
6
+ require "bundler/inline"
7
+
8
+ gemfile(true) do
9
+ source "https://rubygems.org"
10
+
11
+ gem 'uni_rails'
12
+ gem 'puma'
13
+ end
14
+
15
+ require 'uni_rails'
16
+ require 'rack/handler/puma'
17
+
18
+ UniRails.rackup_handler = Rack::Handler::Puma
19
+
20
+ UniRails::App.routes.append do
21
+ root 'pages#index'
22
+ end
23
+
24
+ class PagesController < ActionController::Base
25
+ def index
26
+ render plain: 'Application served by Puma'
27
+ end
28
+ end
29
+
30
+ UniRails.run(Port: 3000)
@@ -0,0 +1,103 @@
1
+ # Run the application
2
+ # $ ruby todos-api.rb
3
+
4
+ ENV['SECRET_KEY_BASE'] = 'my_secret_key_base'
5
+ ENV['DATABASE_URL'] = "sqlite3:///#{Dir.pwd}/todos-api.sqlite"
6
+
7
+ require "bundler/inline"
8
+
9
+ gemfile(true) do
10
+ source "https://rubygems.org"
11
+
12
+ gem 'uni_rails'
13
+ gem 'sqlite3', '~> 1.7'
14
+ end
15
+
16
+ require 'uni_rails'
17
+ require 'sqlite3'
18
+
19
+ ActiveRecord::Base.establish_connection
20
+ ActiveRecord::Schema.define do
21
+ create_table :todos, force: :cascade do |t|
22
+ t.string :name
23
+ t.datetime :completed_at
24
+ t.timestamps
25
+ end
26
+ end
27
+
28
+ UniRails::App.routes.append do
29
+ resources :todos do
30
+ put :complete, on: :member
31
+ end
32
+ end
33
+
34
+ # MODELS
35
+
36
+ class Todo < ActiveRecord::Base
37
+ validates :name, presence: true
38
+
39
+ def complete(at: Time.zone.now)
40
+ update(completed_at: at)
41
+ end
42
+ end
43
+
44
+ # CONTROLLERS
45
+
46
+ class ApplicationController < ActionController::Base
47
+ protect_from_forgery with: :null_session
48
+ end
49
+
50
+ class TodosController < ApplicationController
51
+ before_action :set_todo, only: [:show, :update, :destroy, :complete]
52
+
53
+ def index
54
+ @todos = Todo.all
55
+ render json: @todos
56
+ end
57
+
58
+ def show
59
+ render json: @todo
60
+ end
61
+
62
+ def create
63
+ @todo = Todo.new(todo_params)
64
+ if @todo.save
65
+ render json: @todo, status: :created, location: @todo
66
+ else
67
+ render json: @todo.errors, status: :unprocessable_entity
68
+ end
69
+ end
70
+
71
+ def update
72
+ if @todo.update(todo_params)
73
+ render json: @todo
74
+ else
75
+ render json: @todo.errors, status: :unprocessable_entity
76
+ end
77
+ end
78
+
79
+ def complete
80
+ if @todo.complete
81
+ render json: @todo
82
+ else
83
+ render json: @todo.errors, status: :unprocessable_entity
84
+ end
85
+ end
86
+
87
+ def destroy
88
+ @todo.destroy
89
+ head :no_content
90
+ end
91
+
92
+ private
93
+
94
+ def set_todo
95
+ @todo = Todo.find(params[:id])
96
+ end
97
+
98
+ def todo_params
99
+ params.require(:todo).permit(:name, :status)
100
+ end
101
+ end
102
+
103
+ UniRails.run(Port: 3000)
@@ -0,0 +1,263 @@
1
+ # Based on the Hotwire tutorial: https://www.colby.so/posts/turbo-rails-101-todo-list
2
+ # Run the application
3
+ # $ ruby todos-hotwire.rb
4
+
5
+ ENV['SECRET_KEY_BASE'] = 'my_secret_key_base'
6
+ ENV['DATABASE_URL'] = "sqlite3:///#{Dir.pwd}/todos-hotwire.sqlite"
7
+
8
+ require "bundler/inline"
9
+
10
+ gemfile(true) do
11
+ source "https://rubygems.org"
12
+
13
+ gem 'uni_rails'
14
+ gem 'sqlite3', '~> 1.7'
15
+ gem 'debug'
16
+ end
17
+
18
+ require 'uni_rails'
19
+ require 'sqlite3'
20
+
21
+ ActiveRecord::Base.establish_connection
22
+ ActiveRecord::Schema.define do
23
+ create_table :todos, force: :cascade do |t|
24
+ t.string :name
25
+ t.integer :status, default: 0
26
+ t.timestamps
27
+ end
28
+ end
29
+
30
+ UniRails.enable_turbo_rails!
31
+
32
+ UniRails::App.routes.append do
33
+ root 'todos#index'
34
+ resources :todos do
35
+ patch :change_status, on: :member
36
+ end
37
+ end
38
+
39
+ # MODELS
40
+
41
+ class Todo < ActiveRecord::Base
42
+ enum status: {
43
+ incomplete: 0,
44
+ complete: 1
45
+ }
46
+
47
+ validates :name, presence: true
48
+ end
49
+
50
+
51
+ # CONTROLLERS
52
+
53
+ class TodosController < ActionController::Base
54
+ layout 'application'
55
+
56
+ before_action :set_todo, only: [:edit, :update, :destroy, :change_status]
57
+
58
+ def index
59
+ @todos = Todo.where(status: params[:status].presence || 'incomplete')
60
+ end
61
+
62
+ def new
63
+ @todo = Todo.new
64
+ end
65
+
66
+ def edit
67
+ @todo = Todo.find(params[:id])
68
+ end
69
+
70
+ def create
71
+ @todo = Todo.new(todo_params)
72
+
73
+ respond_to do |format|
74
+ if @todo.save
75
+ format.turbo_stream
76
+ format.html { redirect_to todo_url(@todo), notice: "Todo was successfully created." }
77
+ else
78
+ format.turbo_stream { render turbo_stream: turbo_stream.replace("#{helpers.dom_id(@todo)}_form", partial: "form", locals: { todo: @todo }) }
79
+ format.html { render :new, status: :unprocessable_entity }
80
+ end
81
+ end
82
+ end
83
+
84
+ def update
85
+ respond_to do |format|
86
+ if @todo.update(todo_params)
87
+ format.turbo_stream
88
+ format.html { redirect_to todo_url(@todo), notice: "Todo was successfully updated." }
89
+ format.json { render :show, status: :ok, location: @todo }
90
+ else
91
+ format.turbo_stream { render turbo_stream: turbo_stream.replace("#{helpers.dom_id(@todo)}_form", partial: "form", locals: { todo: @todo }) }
92
+ format.html { render :edit, status: :unprocessable_entity }
93
+ format.json { render json: @todo.errors, status: :unprocessable_entity }
94
+ end
95
+ end
96
+ end
97
+
98
+ def destroy
99
+ @todo.destroy
100
+
101
+ respond_to do |format|
102
+ format.turbo_stream { render turbo_stream: turbo_stream.remove("#{helpers.dom_id(@todo)}_container") }
103
+ format.html { redirect_to todos_url, notice: "Todo was successfully destroyed." }
104
+ format.json { head :no_content }
105
+ end
106
+ end
107
+
108
+ def change_status
109
+ @todo.update(status: todo_params[:status])
110
+ respond_to do |format|
111
+ format.turbo_stream { render turbo_stream: turbo_stream.remove("#{helpers.dom_id(@todo)}_container") }
112
+ format.html { redirect_to todos_path, notice: "Updated todo status." }
113
+ end
114
+ end
115
+
116
+ private
117
+
118
+ def set_todo
119
+ @todo = Todo.find(params[:id])
120
+ end
121
+
122
+ def todo_params
123
+ params.require(:todo).permit(:name, :status)
124
+ end
125
+ end
126
+
127
+ # VIEWS
128
+
129
+ UniRails.javascript <<~JAVASCRIPT
130
+ import * as Turbo from "turbo"
131
+ JAVASCRIPT
132
+
133
+ UniRails.register_view "layouts/application.html.erb", <<~'HTML'
134
+ <!DOCTYPE html>
135
+ <html>
136
+ <head>
137
+ <title>Template</title>
138
+ <meta name="viewport" content="width=device-width,initial-scale=1">
139
+ <%= csrf_meta_tags %>
140
+ <%= csp_meta_tag %>
141
+ <script src="https://cdn.tailwindcss.com"></script>
142
+ <%= uni_rails_css_stylesheet %>
143
+ <%= uni_rails_import_map_tag %>
144
+ <%= uni_rails_javascript_script %>
145
+ </head>
146
+
147
+ <body>
148
+ <%= yield %>
149
+ </body>
150
+ </html>
151
+ HTML
152
+
153
+ UniRails.register_view "todos/index.html.erb", <<~'HTML'
154
+ <div class="mx-auto w-1/2">
155
+ <h2 class="text-2xl text-gray-900">
156
+ Your todos
157
+ </h2>
158
+ <%= turbo_frame_tag "todos-container", class: "block max-w-2xl w-full bg-gray-100 py-8 px-4 border border-gray-200 rounded shadow-sm" do %>
159
+ <div class="border-b border-gray-200 w-full">
160
+ <ul class="flex space-x-2 justify-center">
161
+ <li>
162
+ <%= link_to "Incomplete",
163
+ todos_path(status: "incomplete"),
164
+ class: "inline-block py-4 px-4 text-sm font-medium text-center text-gray-500 border-b-2 border-transparent hover:text-gray-600 hover:border-gray-300"
165
+ %>
166
+ <li>
167
+ <%= link_to "Complete",
168
+ todos_path(status: "complete"),
169
+ class: "inline-block py-4 px-4 text-sm font-medium text-center text-gray-500 border-b-2 border-transparent hover:text-gray-600 hover:border-gray-300"
170
+ %>
171
+ </li>
172
+ </ul>
173
+ </div>
174
+ <% unless params[:status] == "complete" %>
175
+ <div class="py-2 px-4">
176
+ <%= render "form", todo: Todo.new %>
177
+ </div>
178
+ <% end %>
179
+ <ul id="todos">
180
+ <%= render @todos %>
181
+ </ul>
182
+ <% end %>
183
+ </div>
184
+ HTML
185
+
186
+ UniRails.register_view "todos/_form.html.erb", <<~'HTML'
187
+ <%= form_with(model: todo, id: "#{dom_id(todo)}_form") do |form| %>
188
+ <% if todo.errors.any? %>
189
+ <div id="error_explanation" class="bg-red-50 text-red-500 px-3 py-2 font-medium rounded-lg mt-3">
190
+ <h2><%= pluralize(todo.errors.count, "error") %> prohibited this todo from being saved:</h2>
191
+
192
+ <ul>
193
+ <% todo.errors.each do |error| %>
194
+ <li><%= error.full_message %></li>
195
+ <% end %>
196
+ </ul>
197
+ </div>
198
+ <% end %>
199
+ <div class="flex items-stretch flex-grow">
200
+ <%= form.label :name, class: "sr-only" %>
201
+ <%= form.text_field :name, class: "block w-full rounded-none rounded-l-md sm:text-sm border-gray-300", placeholder: "Add a new todo..." %>
202
+ <%= form.submit class: "-ml-px relative px-4 py-2 border border-blue-600 text-sm font-medium rounded-r-md text-white bg-blue-600 hover:bg-blue-700" %>
203
+ </div>
204
+ <% end %>
205
+ HTML
206
+
207
+ UniRails.register_view "todos/_todo.html.erb", <<~'HTML'
208
+ <li id="<%= "#{dom_id(todo)}_container" %>" class="py-2 px-4 border-b border-gray-300">
209
+ <%= turbo_frame_tag dom_id(todo) do %>
210
+ <div class="flex justify-between items-center space-x-2">
211
+ <%= link_to todo.name, edit_todo_path(todo), class: todo.complete? ? 'line-through' : '' %>
212
+
213
+ <div class="flex justify-end space-x-3">
214
+ <% if todo.complete? %>
215
+ <%= button_to change_status_todo_path(todo, todo: { status: 'incomplete' }), class: "bg-green-600 px-4 py-2 rounded hover:bg-green-700", method: :patch do %>
216
+ <span class="sr-only">Mark as incomplete</span>
217
+ <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-white" viewBox="0 0 20 20" fill="currentColor">
218
+ <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd" />
219
+ </svg>
220
+ <% end %>
221
+ <% else %>
222
+ <%= button_to change_status_todo_path(todo, todo: { status: 'complete' }), class: "bg-gray-400 px-4 py-2 rounded hover:bg-green-700", method: :patch do %>
223
+ <span class="sr-only">Mark as complete</span>
224
+ <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-white" viewBox="0 0 20 20" fill="currentColor">
225
+ <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd" />
226
+ </svg>
227
+ <% end %>
228
+ <% end %>
229
+
230
+ <%= button_to todo_path(todo), class: "bg-red-600 px-4 py-2 rounded hover:bg-red-700", method: :delete do %>
231
+ <span class="sr-only">Delete</span>
232
+ <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-white" viewBox="0 0 20 20" fill="currentColor" title="Delete todo">
233
+ <path fill-rule="evenodd" d="M9 2a1 1 0 00-.894.553L7.382 4H4a1 1 0 000 2v10a2 2 0 002 2h8a2 2 0 002-2V6a1 1 0 100-2h-3.382l-.724-1.447A1 1 0 0011 2H9zM7 8a1 1 0 012 0v6a1 1 0 11-2 0V8zm5-1a1 1 0 00-1 1v6a1 1 0 102 0V8a1 1 0 00-1-1z" clip-rule="evenodd" />
234
+ </svg>
235
+ <% end %>
236
+ </div>
237
+ </div>
238
+ <% end %>
239
+ </li>
240
+ HTML
241
+
242
+ UniRails.register_view "todos/edit.html.erb", <<~'HTML'
243
+ <%= turbo_frame_tag dom_id(@todo) do %>
244
+ <%= render "form", todo: @todo %>
245
+ <% end %>
246
+ HTML
247
+
248
+ UniRails.register_view "todos/create.turbo_stream.erb", <<~'HTML'
249
+ <%= turbo_stream.prepend "todos" do %>
250
+ <%= render "todo", todo: @todo %>
251
+ <% end %>
252
+ <%= turbo_stream.replace "#{dom_id(Todo.new)}_form" do %>
253
+ <%= render "form", todo: Todo.new %>
254
+ <% end %>
255
+ HTML
256
+
257
+ UniRails.register_view "todos/update.turbo_stream.erb", <<~'HTML'
258
+ <%= turbo_stream.replace "#{dom_id(@todo)}_container" do %>
259
+ <%= render "todo", todo: @todo %>
260
+ <% end %>
261
+ HTML
262
+
263
+ UniRails.run(Port: 3000)
@@ -0,0 +1,237 @@
1
+ # Run the application
2
+ # $ ruby todos-scaffold.rb
3
+
4
+ ENV['SECRET_KEY_BASE'] = 'my_secret_key_base'
5
+ ENV['DATABASE_URL'] = "sqlite3:///#{Dir.pwd}/todos-scaffold.sqlite"
6
+
7
+ require "bundler/inline"
8
+
9
+ gemfile(true) do
10
+ source "https://rubygems.org"
11
+
12
+ gem 'uni_rails'
13
+ gem 'sqlite3', '~> 1.7'
14
+ gem 'jbuilder' # jbuilder allows the .jbuilder extension for views
15
+ end
16
+
17
+ require 'uni_rails'
18
+ require 'sqlite3'
19
+
20
+ ActiveRecord::Base.establish_connection
21
+ ActiveRecord::Schema.define do
22
+ create_table :todos, force: :cascade do |t|
23
+ t.string :name
24
+ t.datetime :completed_at
25
+ t.timestamps
26
+ end
27
+ end
28
+
29
+ UniRails::App.routes.append do
30
+ root 'todos#index'
31
+ resources :todos
32
+ end
33
+
34
+ # MODELS
35
+
36
+ class Todo < ActiveRecord::Base
37
+ validates :name, presence: true
38
+
39
+ def complete(at: Time.zone.now)
40
+ update(completed_at: at)
41
+ end
42
+ end
43
+
44
+
45
+ # CONTROLLERS
46
+ class ApplicationController < ActionController::Base
47
+ end
48
+
49
+ class TodosController < ApplicationController
50
+ before_action :set_todo, only: %i[ show edit update destroy ]
51
+
52
+ # GET /todos or /todos.json
53
+ def index
54
+ @todos = Todo.all
55
+ end
56
+
57
+ # GET /todos/1 or /todos/1.json
58
+ def show
59
+ end
60
+
61
+ # GET /todos/new
62
+ def new
63
+ @todo = Todo.new
64
+ end
65
+
66
+ # GET /todos/1/edit
67
+ def edit
68
+ end
69
+
70
+ # POST /todos or /todos.json
71
+ def create
72
+ @todo = Todo.new(todo_params)
73
+
74
+ respond_to do |format|
75
+ if @todo.save
76
+ format.html { redirect_to todo_url(@todo), notice: "Todo was successfully created." }
77
+ format.json { render :show, status: :created, location: @todo }
78
+ else
79
+ format.html { render :new, status: :unprocessable_entity }
80
+ format.json { render json: @todo.errors, status: :unprocessable_entity }
81
+ end
82
+ end
83
+ end
84
+
85
+ # PATCH/PUT /todos/1 or /todos/1.json
86
+ def update
87
+ respond_to do |format|
88
+ if @todo.update(todo_params)
89
+ format.html { redirect_to todo_url(@todo), notice: "Todo was successfully updated." }
90
+ format.json { render :show, status: :ok, location: @todo }
91
+ else
92
+ format.html { render :edit, status: :unprocessable_entity }
93
+ format.json { render json: @todo.errors, status: :unprocessable_entity }
94
+ end
95
+ end
96
+ end
97
+
98
+ # DELETE /todos/1 or /todos/1.json
99
+ def destroy
100
+ @todo.destroy!
101
+
102
+ respond_to do |format|
103
+ format.html { redirect_to todos_url, notice: "Todo was successfully destroyed." }
104
+ format.json { head :no_content }
105
+ end
106
+ end
107
+
108
+ private
109
+ # Use callbacks to share common setup or constraints between actions.
110
+ def set_todo
111
+ @todo = Todo.find(params[:id])
112
+ end
113
+
114
+ # Only allow a list of trusted parameters through.
115
+ def todo_params
116
+ params.require(:todo).permit(:name, :completed_at)
117
+ end
118
+ end
119
+
120
+ # VIEWS - HTML
121
+
122
+ UniRails.register_view "todos/_form.html.erb", <<~HTML
123
+ <%= form_with(model: todo) do |form| %>
124
+ <% if todo.errors.any? %>
125
+ <div style="color: red">
126
+ <h2><%= pluralize(todo.errors.count, "error") %> prohibited this todo from being saved:</h2>
127
+
128
+ <ul>
129
+ <% todo.errors.each do |error| %>
130
+ <li><%= error.full_message %></li>
131
+ <% end %>
132
+ </ul>
133
+ </div>
134
+ <% end %>
135
+
136
+ <div>
137
+ <%= form.label :name, style: "display: block" %>
138
+ <%= form.text_field :name %>
139
+ </div>
140
+
141
+ <div>
142
+ <%= form.label :completed_at, style: "display: block" %>
143
+ <%= form.datetime_field :completed_at %>
144
+ </div>
145
+
146
+ <div>
147
+ <%= form.submit %>
148
+ </div>
149
+ <% end %>
150
+ HTML
151
+
152
+ UniRails.register_view "todos/_todo.html.erb", <<~HTML
153
+ <div id="<%= dom_id todo %>">
154
+ <p>
155
+ <strong>Name:</strong>
156
+ <%= todo.name %>
157
+ </p>
158
+
159
+ <p>
160
+ <strong>Completed at:</strong>
161
+ <%= todo.completed_at %>
162
+ </p>
163
+
164
+ </div>
165
+ HTML
166
+
167
+ UniRails.register_view "todos/edit.html.erb", <<~HTML
168
+ <h1>Editing todo</h1>
169
+
170
+ <%= render "form", todo: @todo %>
171
+
172
+ <br>
173
+
174
+ <div>
175
+ <%= link_to "Show this todo", @todo %> |
176
+ <%= link_to "Back to todos", todos_path %>
177
+ </div>
178
+ HTML
179
+
180
+ UniRails.register_view "todos/index.html.erb", <<~HTML
181
+ <p style="color: green"><%= notice %></p>
182
+
183
+ <h1>Todos</h1>
184
+
185
+ <div id="todos">
186
+ <% @todos.each do |todo| %>
187
+ <%= render todo %>
188
+ <p>
189
+ <%= link_to "Show this todo", todo %>
190
+ </p>
191
+ <% end %>
192
+ </div>
193
+
194
+ <%= link_to "New todo", new_todo_path %>
195
+ HTML
196
+
197
+ UniRails.register_view "todos/new.html.erb", <<~HTML
198
+ <h1>New todo</h1>
199
+
200
+ <%= render "form", todo: @todo %>
201
+
202
+ <br>
203
+
204
+ <div>
205
+ <%= link_to "Back to todos", todos_path %>
206
+ </div>
207
+ HTML
208
+
209
+ UniRails.register_view "todos/show.html.erb", <<~HTML
210
+ <p style="color: green"><%= notice %></p>
211
+
212
+ <%= render @todo %>
213
+
214
+ <div>
215
+ <%= link_to "Edit this todo", edit_todo_path(@todo) %> |
216
+ <%= link_to "Back to todos", todos_path %>
217
+
218
+ <%= button_to "Destroy this todo", @todo, method: :delete %>
219
+ </div>
220
+ HTML
221
+
222
+ # VIEWS - JSON
223
+
224
+ UniRails.register_view "todos/_todo.json.jbuilder", <<~RUBY
225
+ json.extract! todo, :id, :name, :completed_at, :created_at, :updated_at
226
+ json.url todo_url(todo, format: :json)
227
+ RUBY
228
+
229
+ UniRails.register_view "todos/index.json.jbuilder", <<~RUBY
230
+ json.array! @todos, partial: "todos/todo", as: :todo
231
+ RUBY
232
+
233
+ UniRails.register_view "todos/show.json.jbuilder", <<~RUBY
234
+ json.partial! "todos/todo", todo: @todo
235
+ RUBY
236
+
237
+ UniRails.run(Port: 3000)
@@ -3,12 +3,8 @@ module UniRails
3
3
  class CSS
4
4
  include Singleton
5
5
 
6
- def self.css=(content)
7
- instance.css = content
8
- end
9
-
10
- def self.css
11
- instance.css
6
+ class << self
7
+ delegate :css, :css=, to: :instance
12
8
  end
13
9
 
14
10
  attr_accessor :css
@@ -3,20 +3,11 @@ module UniRails
3
3
  class Javascript
4
4
  include Singleton
5
5
 
6
- def self.imports
7
- instance.imports
8
- end
9
-
10
- def self.dependencies=(dependencies)
11
- instance.dependencies = dependencies
12
- end
13
-
14
- def self.javascript
15
- instance.javascript
16
- end
17
-
18
- def self.javascript=(content)
19
- instance.javascript = content
6
+ class << self
7
+ delegate :imports,
8
+ :dependencies, :dependencies=,
9
+ :javascript, :javascript=,
10
+ to: :instance
20
11
  end
21
12
 
22
13
  attr_accessor :dependencies, :javascript
data/lib/uni_rails/app.rb CHANGED
@@ -1,8 +1,8 @@
1
1
  # Pick the frameworks you want:
2
2
 
3
- # require "active_model/railtie"
3
+ require "active_model/railtie"
4
4
  # require "active_job/railtie"
5
- require "active_record/railtie"
5
+ require "active_record/railtie" unless ENV['DATABASE_URL'].nil?
6
6
  # require "active_storage/engine"
7
7
  require "action_controller/railtie"
8
8
  # require "action_mailer/railtie"
@@ -15,10 +15,12 @@ require "action_view/testing/resolvers"
15
15
 
16
16
  module UniRails
17
17
  class App < Rails::Application
18
+ config.load_defaults 7.1
19
+
18
20
  config.eager_load = true
19
21
  config.logger = Logger.new(STDOUT)
20
22
  config.log_level = :debug
21
- config.secret_key_base = "whatever"
23
+ config.secret_key_base = ENV.fetch('SECRET_KEY_BASE')
22
24
 
23
25
  config.after_initialize do
24
26
  ActionController::Base.view_paths = Views.view_paths
@@ -1,7 +1,7 @@
1
1
  module UniRails
2
2
  module Helpers
3
3
  module CSSHelper
4
- def mono_rails_css_stylesheet
4
+ def uni_rails_css_stylesheet
5
5
  content_tag(:style) do
6
6
  raw App::CSS.css
7
7
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module UniRails
4
- VERSION = "0.2.1"
4
+ VERSION = "0.3.0"
5
5
  end
data/lib/uni_rails.rb CHANGED
@@ -1,5 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ if ENV['SECRET_KEY_BASE'].nil?
4
+ raise StandardError, <<~ERROR
5
+
6
+ SECRET_KEY_BASE environment variable is required
7
+ Provide ENV['SECRET_KEY_BASE'] in your file or export the variable to your profile
8
+ ERROR
9
+ end
10
+
3
11
  require "rails"
4
12
  require_relative "uni_rails/version"
5
13
  require_relative "uni_rails/helpers"
@@ -13,19 +21,52 @@ require_relative "uni_rails/app/views"
13
21
  module UniRails
14
22
  class Error < StandardError; end
15
23
 
24
+ def self.enable_turbo_rails!
25
+ # # We currently do not support ActionCable and ActiveJob
26
+ require "turbo-rails"
27
+
28
+ App.configure do
29
+ initializer "turbo.no_action_cable", before: :set_eager_load_paths do
30
+ unless defined?(ActionCable)
31
+ Rails.autoloaders.once.do_not_eager_load("#{Turbo::Engine.root}/app/channels")
32
+ end
33
+
34
+ unless defined?(ActiveJob)
35
+ Rails.autoloaders.once.do_not_eager_load("#{Turbo::Engine.root}/app/jobs")
36
+ end
37
+ end
38
+ end
39
+
40
+ App::Javascript.dependencies.merge!(
41
+ "turbo" => "https://unpkg.com/@hotwired/turbo@8.0.4/dist/turbo.es2017-umd.js"
42
+ )
43
+ end
44
+
45
+ def self.rackup_handler=(handler)
46
+ @@rackup_handler = handler
47
+ end
48
+
49
+ def self.rackup_handler
50
+ @@rackup_handler ||= begin
51
+ require 'rackup'
52
+ Rackup::Handler::WEBrick
53
+ end
54
+ end
55
+
16
56
  def self.register_view(action, view)
17
57
  UniRails::App::Views.instance.views[action] = view
18
58
  end
19
59
 
20
60
  def self.run(**webrick_options)
21
61
  App.initialize!
22
- # Rackup::Handler::WEBrick.run App, **webrick_options
62
+ rackup_handler.run App, **webrick_options
23
63
  # Rackup::Handler::Falcon.run App, **webrick_options
24
- Rack::Handler::Puma.run App, **webrick_options
64
+ # Rack::Handler::Puma.run App, **webrick_options
65
+ # Rackup::Handler::WEBrick.run App, **webrick_options
25
66
  end
26
67
 
27
68
  def self.import_maps(dependencies)
28
- UniRails::App::Javascript.dependencies = dependencies
69
+ UniRails::App::Javascript.dependencies.merge! dependencies
29
70
  end
30
71
 
31
72
  def self.javascript(content)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: uni_rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alexandre Barret
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-03-30 00:00:00.000000000 Z
11
+ date: 2024-04-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -24,6 +24,34 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '7.1'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rackup
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '2.1'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '2.1'
41
+ - !ruby/object:Gem::Dependency
42
+ name: turbo-rails
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '2.0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '2.0'
27
55
  description:
28
56
  email:
29
57
  - barret.alx@gmail.com
@@ -35,9 +63,12 @@ files:
35
63
  - LICENSE.txt
36
64
  - README.md
37
65
  - Rakefile
38
- - examples/hotwire.rb
39
- - examples/json_api.rb
40
- - examples/todos.rb
66
+ - examples/hello-world.rb
67
+ - examples/server-falcon-app.rb
68
+ - examples/server-puma-app.rb
69
+ - examples/todos-api.rb
70
+ - examples/todos-hotwire.rb
71
+ - examples/todos-scaffold.rb
41
72
  - lib/uni_rails.rb
42
73
  - lib/uni_rails/app.rb
43
74
  - lib/uni_rails/app/css.rb
@@ -69,7 +100,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
69
100
  - !ruby/object:Gem::Version
70
101
  version: '0'
71
102
  requirements: []
72
- rubygems_version: 3.4.21
103
+ rubygems_version: 3.5.3
73
104
  signing_key:
74
105
  specification_version: 4
75
106
  summary: A Ruby library to create single-file Rails application
data/examples/hotwire.rb DELETED
File without changes
data/examples/json_api.rb DELETED
File without changes
data/examples/todos.rb DELETED
File without changes