Component based Rails architecture

In lib/app_running_mode.rb

We can set ENV['APP_RUNNING_MODE'] to public/api or empty when you deploy which you can split your app to public_app or api_app.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class AppRunningMode
class << self
def value
case downcased_app_running_mode_env
when 'public'
:public
when 'api'
:api
else
:development
end
end

def bundler_groups
case value
when :public
[:public_app]
when :api
[:api_app]
else
[:public_app, :api_app]
end
end

private

def downcased_app_running_mode_env
if ENV['APP_RUNNING_MODE']
return ENV['APP_RUNNING_MODE'].downcase
end
end
end
end

In application.rb

Add more groups for Gemfile.

1
Bundler.require(*Rails.groups + AppRunningMode.bundler_groups)

In routes.rb

Include different routes.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
case AppRunningMode.value
when :api
mount ApiComponent::Engine, at: '/api'
# mount activeadmin routes with api component
# you can mount with public if necessary(depend on traffic)
# or you can separate it to an admin component if you want
ActiveAdmin.routes(self)
when :public
mount PublicComponent::Engine, at: '/'
else
mount ApiComponent::Engine, at: '/api'
mount PublicComponent::Engine, at: '/'
ActiveAdmin.routes(self)
end

In Gemfile

Bundle diff gem(generated by Rails engin) by you ENV[‘APP_RUNNING_MODE’] you specify.

1
2
3
4
5
6
7
8
9
10
11
group :api_app do
path 'components' do
gem 'api_component'
end
end

group :public_app do
path 'components' do
gem 'public_component'
end
end