Ruby Open Source: Zammad example

lucianghinda

Lucian Ghinda

Posted on November 10, 2023

Ruby Open Source: Zammad example

Another example of an open source web app written in Ruby

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.

What is Zammad

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

Ruby Version and Rails version

Licensing

The license is GNU AGPL

License of the repo

They mention on their website why they chose to make the product open source:

About open source

Each file in the repository has a license line like:

Copyright line in the repo

Some ideas from the open-source repo

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

Stats

Running rails stats returned the following:

Result of executing rails stats on the repo

Styling Guide

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
Enter fullscreen mode Exit fullscreen mode

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 with exists?

  • 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

Persistence

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.

gems used for persistence

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
Enter fullscreen mode Exit fullscreen mode

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

Some gems used

  • 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"

Design Patterns

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:

Service Base object

The primary 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::HasQueuingPriority that looks like this:

Application Job

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:

ApplicationModel object

There are probably many 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. For more Ruby learning resources, visit rubyandrails.info. You can also find me on Ruby.social or Linkedin or Twitter.

💖 💪 🙅 🚩
lucianghinda
Lucian Ghinda

Posted on November 10, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related

Ruby Open Source: Zammad example
ruby Ruby Open Source: Zammad example

November 10, 2023