solid-rails-app
solid-rails-app copied to clipboard
Twelve versions (gradually implemented) of a Web and REST API to demonstrate how Solid::Process can add value to a Ruby on Rails application.
✨ Solid Rails App
Web and REST API application made with Ruby on Rails + solid-process.
🙌 Repository branches
This repository has three branches:
- vanilla-rails:
100%Rails way +0%solid-process. - main:
95%Rails way +5%solid-process. (📍 you are here) - solid-process:
20%Rails way +80%solid-process.
📊 Rails stats and code quality
| Branch | LOC | Rubycritic | Tests coverage |
|---|---|---|---|
| vanilla-rails | 1407 | 94.26 | 98.5% |
| main | 1517 | 94.30 | 98.57% |
| solid-process | 1883 | 93.93 | 97.13% |
Use:
bin/rails testto generate the tests coverage report.bin/rails statsto generate the LOC report.bin/rails rubycriticto generate the rubycritic (code quality) report.
📢 Disclaimer
The goal of this branch is to show how the solid-process can be progressively introduced into a Rails application (check out the User::Registration).
You can use it only where you see fit, and you don't need to choose between one approach (Rails Way) or another (solid-process), as both can coexist in a complementary and friendly way.
🌟 Highlights of what solid-process can bring to you
-
The
solid-processuses Rails's known components, such as ActiveModel attributes, validations, callbacks, and more. This way, you can use the same tools you are already familiar with. -
A way for representing/writing critical system operations. It feels like having code that documents itself. You can see the operation's steps, inputs, outputs, side effects, and more in one place.
-
A less coupled codebase, given that this structure encourages the creation of cohesive operations (with a specific purpose), thus reducing the concentration of logic in ActiveRecord models.
e.g., several callbacks from the
Usermodel were replaced by theUser::Registrationprocess. -
Standardization of instrumentation and observability of what occurs within each process (Implement a listener to do this automatically and transparently for the developer [1]). This will help you better understand what is happening within the system.
User::Registration event logs sample:
#0 User::Registration * Given(email:, password:, password_confirmation:) * Continue(user:) from method: create_user * Continue(account:) from method: create_user_account * Continue() from method: create_user_inbox * Continue() from method: create_user_token * Continue() from method: send_email_confirmation * Success(:user_registered, user:)
-
The file structure reveals the system's critical processes, making it easier to understand its behavior and find where to make changes. Check out the app/models directory.
app/modelsfile structure (checkout the solid-process branch to see a more complete example):app/models/user └── registration.rb
🤔 How do we be aware of the system's critical processes?
Use the following command to generate a list of all processes in the system:
bin/rails solid:processes
Lines:
62 ./app/models/user/registration.rb
Files: 1
📚 Table of contents
- System dependencies
- Setup
- How to run the test suite
- How to run the application locally
- API Documentation (cURL examples)
- User
- Registration
- Authentication
- Account deletion
- Access token updating
- Password updating
- Password resetting - Link to change the password
- Password resetting - Change the password
- Task List
- Listing
- Creation
- Updating
- Deletion
- Task
- Listing
- Creation
- Updating
- Deletion
- Marking as completed
- Marking as incomplete
- User
- Web app screenshots
System dependencies
- SQLite3
- Ruby
3.2.3- bundler
>= 2.5.6
- bundler
Setup
- Install system dependencies
- Create a
config/master.keyfile with the following content:
echo 'a061933f96843c82342fb8ab9e9db503' > config/master.key
chmod 600 config/master.key
- Run
bin/setup
How to run the test suite
bin/rails test
How to run the application locally
bin/rails s- Open in your browser:
http://localhost:3000
API Documentation (cURL examples)
Set the following environment variables to use the examples below:
export API_HOST="http://localhost:3000"
export API_TOKEN="MY_ACCESS_TOKEN"
You can get the API_TOKEN by:
- Using the below
User / Registrationrequest. - or performing the below
User / Authenticationrequest. - or copying the
access_tokenfromSign In >> Settings >> APIpage.
User
Registration
curl -X POST "$API_HOST/api/v1/user/registrations" \
-H "Content-Type: application/json" \
-d '{
"user": {
"email": "[email protected]",
"password": "123123123",
"password_confirmation": "123123123"
}
}'
Authentication
curl -X POST "$API_HOST/api/v1/user/sessions" \
-H "Content-Type: application/json" \
-d '{
"user": {
"email": "[email protected]",
"password": "123123123"
}
}'
Account deletion
curl -X DELETE "$API_HOST/api/v1/user/registrations" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $API_TOKEN"
Access token updating
curl -X PUT "$API_HOST/api/v1/user/tokens" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $API_TOKEN"
Password updating
curl -X PUT "$API_HOST/api/v1/user/passwords" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $API_TOKEN" \
-d '{
"user": {
"current_password": "123123123",
"password": "321321321",
"password_confirmation": "321321321"
}
}'
Password resetting - Link to change the password
curl -X POST "$API_HOST/api/v1/user/passwords/reset" \
-H "Content-Type: application/json" \
-d '{"user": {"email": "[email protected]"}}'
Password resetting - Change the password
curl -X PUT "$API_HOST/api/v1/user/passwords/reset" \
-H "Content-Type: application/json" \
-d '{
"user": {
"token": "TOKEN_RETRIEVED_BY_EMAIL",
"password": "123123123",
"password_confirmation": "123123123"
}
}'
Task List
Listing
curl -X GET "$API_HOST/api/v1/task/lists" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $API_TOKEN"
Creation
curl -X POST "$API_HOST/api/v1/task/lists" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $API_TOKEN" \
-d '{"task_list": {"name": "My Task List"}}'
Updating
curl -X PUT "$API_HOST/api/v1/task/lists/2" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $API_TOKEN" \
-d '{"task_list": {"name": "My List"}}'
Deletion
curl -X DELETE "$API_HOST/api/v1/task/lists/2" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $API_TOKEN"
Task
Listing
# ?filter=completed | incomplete
curl -X GET "$API_HOST/api/v1/task/lists/1/items" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $API_TOKEN"
Creation
curl -X POST "$API_HOST/api/v1/task/lists/1/items" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $API_TOKEN" \
-d '{"task": {"name": "My Task"}}'
Updating
# "completed": true | 1 | false | 0
curl -X PUT "$API_HOST/api/v1/task/lists/1/items/1" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $API_TOKEN" \
-d '{"task": {"name": "My Task", "completed": true}}'
Deletion
curl -X DELETE "$API_HOST/api/v1/task/lists/1/items/1" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $API_TOKEN"
Marking as completed
curl -X PUT "$API_HOST/api/v1/task/lists/1/items/1/complete" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $API_TOKEN"
Marking as incomplete
curl -X PUT "$API_HOST/api/v1/task/lists/1/items/1/incomplete" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $API_TOKEN"
Web app screenshots
Sign in
Forgot password
Sign up
Tasks
Task Lists
Settings
Sign out