title | seoTitle | seoDescription | datePublished | cuid | slug | cover | tags |
---|---|---|---|---|---|---|---|
Ruby Open Source: Zammad example |
Zammad Ruby on Rails Open Source Example |
Explore Zammad: open-source Ruby ticketing system with cloud, custom styling, multiple databases, and service objects on Ruby 3.1.3, Rails 7 |
Fri Nov 03 2023 03:52:55 GMT+0000 (Coordinated Universal Time) |
cloi2yd2y000c09jtgkw8ceoe |
ruby-open-source-zammad-example |
programming-blogs, ruby, opensource, ruby-on-rails, coding |
I will probably start a series of open-source Ruby Projects. Maybe I will call it #opensource #Friday.
Zammad is an open-source ticketing system, that also offers an on-cloud product.
They have their product open-sourced on Github and it is built using (at the moment of writing this article) Ruby 3.1.3 and Rails 7
The license is GNU AGPL
They mention on their website why they chose to make the product open source:
Each file in the repository has a license line like:
I don't have enough time to analyse in depth the repo. So just looking around for 30 minutes, here are some things that I extracted
Running rails stats
returned the following:
![Result of executing rails stats on the repo](https://cdn.hashnode.com/res/hashnode/image/upload/v1698983056409/424bdfb1-3437-4fb2-a49a-6e421b6066b4.png align="center")
They use Rubocop with extra cops added. They require some cops provided by gems and custom cops written by them:
require:
- rubocop-capybara
- rubocop-factory_bot
- rubocop-faker
- rubocop-graphql
- rubocop-inflector
- rubocop-performance
- rubocop-rails
- rubocop-rspec
- ../config/initializers/inflections.rb
- ./rubocop_zammad.rb
In rubocop_zammad.rb
they are loading custom cops from .rubocop/cop/zammad
Here are some custom cops written by them:
-
Checking if the migration file starts with a valid timestamp
-
Checking usages of
find_by
to check if an Active Record exists and replace it withexists?
-
Checking that the only allowed
default_scope
is about simple ordering -
Checking for using
rand
-
Checking usages of
.to_sym
on strings and change to:
prefix -
Checking usages of
unless
and suggest using!
-
Checking copyright notice and adding it when missing
More about their style guide can be found at doc/developer_manual/standards
They appear to use 3 DBs, each one having their group. One (the activerecord-nulldb-adapter) is actually a NullObject pattern implemented for Active Record.
![](https://cdn.hashnode.com/res/hashnode/image/upload/v1697613005230/e9580f24-8d99-4bf4-a9cd-df14a0726516.png align="center")
Based on the loaded connection they do a preflight check in an initializer. This is what it looks like:
Rails.application.config.after_initialize do
Zammad::Application::Initializer::DbPreflightCheck.perform
end
and you can go check lib/zammad/application/initializer
to see what kind of checks are executed for each adapter.
This is a way to make sure that the actual DB server respects a contract they have defined in these initializers (e.g. what extensions are activated or config defaults or minimum version).
See this example of a check for MySQL from the same file:
![Code sample from MySQL DB preflight check](https://cdn.hashnode.com/res/hashnode/image/upload/v1698982343291/90dad251-2dda-44dc-86e4-842e72de559e.png align="center")
-
argon2 - "A Ruby gem offering bindings for Argon2 password hashing"
-
rszr - "Rszr is an image resizer for Ruby based on the Imlib2 library. It is faster and consumes less memory than MiniMagick, GD2 and VIPS, and comes with an optional drop-in interface for Rails ActiveStorage image processing"
-
biz - "Time calculations using business hours"
-
diffy - "It provides a convenient way to generate a diff from two strings or files. Instead of reimplementing the LCS diff algorithm Diffy uses battle tested Unix diff to generate diffs, and focuses on providing a convenient interface, and getting out of your way"
-
chunky_png - "ChunkyPNG is a pure Ruby library to read and write PNG images and access textual metadata. It has no dependency on RMagick, or any other library for that matter"
-
localhost - "This gem provides a convenient API for generating per-user self-signed root certificates"
-
activerecord-nulldb - "NullDB is the Null Object pattern as applied to ActiveRecord database adapters. It is a database backend that translates database interactions into no-ops. Using NullDB enables you to test your model business logic - including after_save hooks - without ever touching a real database"
They use service objects. There is a Service::Base
class that is empty and then there is also Service::BaseWithCurrentUser
that looks something like this:
The main method that a Service object should define is execute
but there is no enforcement of this. It is just that everything under app/services/service has this method defined.
GraphQL objects
All the logic about GraphQL is inside app/graphql, namescoped to Gql.
Jobs
They can be found at app/jobs. Job priority is defined in a concern called ApplicationJob::HasQueuingPriorit
y
that looks like this:
And all jobs have a default priority of 200 while low_priority is defined as being 300
Models
They are under app/models and there is an ApplicationModel
defined that includes some defaults like this:
There are probably a lot more interesting things to discover about the codebase but this is what I got in a short review.
Enjoyed this article?
👉 Join my Short Ruby News newsletter for weekly Ruby updates from the community and visit rubyandrails.info, a directory with learning content about Ruby.
👐 Subscribe to my Ruby and Ruby on rails courses over email at learn.shortruby.com - effortless learning anytime, anywhere
🤝 Let's connect on Ruby.social or Linkedin or Twitter where I post mainly about Ruby and Rails.
🎥 Follow me on my YouTube channel for short videos about Ruby