- ATOMS and gems are interchangeable.
lib/[this_atom_name].rb
and similar, indicates the file, named after the current gem name, which resides in lib.require '[other_atom]'
and similar, indicates the name of another gem on which the current one is dependant.
Usually an ATOM adds some conventions also on folders and files structure, here is the base structure you'll see more often when dealing with ATOMS:
.
├── Gemfile
├── MIT-LICENSE
├── README.md
├── Rakefile
├── app
│ ├── assets
│ │ ├── javascripts
│ │ │ └── main_tcp_debug.js
│ │ └── stylesheets
│ │ └── main_tcp_debug.scss
│ └── views
│ └── rails_admin
│ └── main
│ └── tcp_debug.html.erb
├── config
│ ├── initializers
│ │ ├── add_to_db_migration.rb
│ │ ├── after_initialize.rb
│ │ └── assets.rb
│ └── locales
│ ├── en.thecore_tcp_debug.yml
│ └── it.thecore_tcp_debug.yml
├── db
│ └── seeds.rb
├── lib
│ ├── root_actions
│ │ └── tcp_debug.rb
│ ├── thecore_tcp_debug
│ │ ├── engine.rb
│ │ └── version.rb
│ └── thecore_tcp_debug.rb
└── thecore_tcp_debug.gemspec
An ATOM can depend on these two base thecore ATOMS. They can added together or just once, be the ATOM an API only gem or a gem which delivers functionalities useful for a GUI experience.
s.add_dependency 'thecore_ui_rails_admin', '~> 3.0'
s.add_dependency 'model_driven_api', '~> 3.0'
The ATOM can depend also on another ATOM, at which point thecore_ui_rails_admin
and/or model_driven_api
are already included in the dependency chain and only the other ATOM needs to be added as a dependency.
It's advised to add in the lib/[this_atom_name].rb
file all the requires pointing to depending ATOMS, for example, whenever you add a dependency in the *.gemspec
file, please add the relevant require '[other_atom]'
to the lib/[this_atom_name].rb
of the current ATOM you are developing.
Here you can find a sample of a sane and comprehensive Git ignore file.
Root Actions are Rails Admin actions which are not directly dependant on a Model. They don't follow CRUD and add a business logic level to the application, in order to provide a more complex interaction witht he User. The menu entry will be rentered in a special section of the menu, outside Model's ones.
They are defined by convention in the lib/root_actions
folder of the gem and follow a specific format, like this example from the Thecore TCP Debug ATOM.
Have a look at the comments in this snippet to bettr understand:
RailsAdmin::Config::Actions.add_action "tcp_debug", :base, :root do
# For the root action's menu item to appear in the right menu, these five ones are mandatory:
show_in_sidebar true
show_in_navigation false
breadcrumb_parent [nil]
member false
collection false
# Icon is the graphical element whch appears besides the menu item, must be chosen from
# FontAwesome available icons:
link_icon 'fas fa-heartbeat'
# The method to interact with the controller section below, can be any HTTP verb, also more than one
http_methods [:get]
# Adding the controller which is needed to compute calls from the ui
controller do
# This is needed because we need that this code is re-evaluated each time is called
# this mins the proc do part is mandatory
proc do
# Not mandatory, but is always useful to distinguish between a REST or an AJAX call.
if request.xhr?
# I can access params passed during the call and use them inside this controller's business logic.
case params["test"]
when "telnet"
port_is_open = Socket.tcp(params["host"], params["port"], connect_timeout: 5) { true } rescue false
message, status = { debug_status: I18n.t("tcp_debug_telnet_ko", host: params["host"].presence || "-", port: params["port"].presence || "-") }, 503
message, status = { debug_status: I18n.t("tcp_debug_telnet_ok", host: params["host"].presence || "-", port: params["port"].presence || "-") }, 200 if port_is_open
when "ping"
check = Net::Ping::External.new(params["host"])
message, status = { debug_status: I18n.t("tcp_debug_ping_ko", host: params["host"].presence || "-") }, 503
message, status = { debug_status: I18n.t("tcp_debug_ping_ok", host: params["host"].presence || "-") }, 200 if check.ping?
else
message, status = { debug_status: I18n.t("invalid_test", host: params["host"]) }, 400
end
# Thecore comes preconfigured to deliver Websocket messages, why not use them to make this
# controller more reactive?
ActionCable.server.broadcast("messages", { topic: :tcp_debug, status: status, message: message})
# It follows the RESTful convention:
render json: message.to_json, status: status
else
Rails.logger.debug "When the request is not an AJAX call."
end
end
end
end
In config/initializers/after_initialize.rb
add the require to load this root action, like: require "root_actions/tcp_debug"
.
In app/views/rails_admin/main/tcp_debug.html.erb
add the HTML that must be rendered to create the UX.
Add all the styles that are only needed in the current Root Action in a file named after the action name defined in RailsAdmin::Config::Actions.add_action
, in this example the right place is: app/assets/stylesheets/main_tcp_debug.scss
.
Please note that the controller is always main in Rails Admin context and the other part is the root action name.
Javascript can be added in two different ways, be it conventionally loadaded in the layout using the controller and action names or embedded in a <script></script>
tag directly in the *.html.erb
file.
Both need to follow some guidelines to be correctly loaded at runtime by both Turbo or a normal RESTful call of the page.
Add all the jvascripts that are only needed in the current Root Action in a file named after the action name defined in RailsAdmin::Config::Actions.add_action
, in this example the right place is: app/assets/stylesheets/main_tcp_debug.js
.
Please note that the controller is always main in Rails Admin context and the other part is the root action name.
To embed the Javascript file directly into the action's .html.erb
file is advised to:
- Surround the code in a
<script></script>
tag. - Put all the variables needed by the events in the root of the script tag.
- Put all the functions at the root of the script tag.
- Put all the business logic into a
document.addEventListener("turbo:load", function (event) { });
listener.
Please keep your wrapper App with Major version equal to the Thecore Major version, i.e. if using thecore 3 gems, then your wrapper App will start at 3.0.0 version, in order to keep it simple to identify on which Thecore base is built your aplication.
In the thecore APP the preferred way to integrate your code is by putting in the Gemfile.base the ATOM which depends on the base thecore ATOMS: Model Driven API and Thecore UI Rails Admin. These are added in a separate way to allow developer to focus on the needed aspects of the application, UI or API based.
gem 'your_business_logic_atom', '~> 3.0'