How to create a Rails-specific Rubygem?

50 views Asked by At

We're building a Chat service, which people are able to use from within their code.

Amongst the tools we're building, we've made a Ruby gem to allow people to quickly add a Chat window to their Ruby web-application.

We'd like to create a Rails-specific wrapper, though, because currently the user has to manually call .html_safe.

How is it possible to use these Rails-specific features from within a Ruby gem? I've heard this might be called 'Railsties' but I have not been able to find any comprehensive documentation about these, and how to use them.

Specifically, we'd like to:

  • Call html_safe on some string output so the user does not have to do this manually.
  • Put some configuration settings in a file in config/initializers/some_name.rb rather than having to specify these inline.
  • Potentially create a generator that the user can run to fill this initializer automatically.

How can we use these features? Is there some other gem-dependency we can include in our gem to access these features?

1

There are 1 answers

1
max On

Engines can be considered miniature applications that provide functionality to their host applications. A Rails application is actually just a "supercharged" engine, with the Rails::Application class inheriting a lot of its behavior from Rails::Engine.
https://guides.rubyonrails.org/engines.html

An engine can contain models, controllers, routes, generators, middleware and any arbitrary code that you can mount in the host application. Engines are usually packaged as gems.

Devise for example is a rails engine that provides authorization.

Rails has a generator command for creating engines:

rails plugin new chatty --mountable

For this example lets call it chatty.

Since an engine is mounted in a Rails application you have full access to the Rails stack (such as .html_safe). This also means that you test engines by mounting them in a dummy application.

If you have packaged the application as a gem than you simply mount it in the host application by adding it to the Gemfile.

To make your engine configurable you can follow the "MyGem.configure pattern":

# lib/chatty.rb
module Chatty
  class << self
    attr_accessor :configuration
  end

  def self.configure
    self.configuration ||= Configuration.new
    yield(configuration)
  end

  class Configuration
    attr_accessor :foo

    def initialize
      @foo = 'some_value'
    end
  end
end

To create a user configuration file you use a generator:

# lib/generators/chatty/install/install_generator.rb
module Chatty
  class InstallGenerator < Rails::Generators::Base
    source_root File.expand_path('templates', __dir__)

    desc "Creates a Chatty initializer."

    def copy_initializer
      template 'chatty.rb', 'config/initializers/chatty.rb'
    end
  end
end

And a code template:

# /lib/generators/chatty/install/templates/chatty.rb
Chatty.configure do |config|
  config.foo = "bar"
end

You can now run rails g chatty:install and it will create the file in the host application.