rails-metro 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +17 -0
- data/LICENSE +21 -0
- data/README.md +267 -0
- data/exe/metro +3 -0
- data/lib/rails/metro/cli.rb +162 -0
- data/lib/rails/metro/config.rb +40 -0
- data/lib/rails/metro/feature_pack.rb +59 -0
- data/lib/rails/metro/feature_registry.rb +147 -0
- data/lib/rails/metro/packs/aasm_pack.rb +29 -0
- data/lib/rails/metro/packs/ab_testing_pack.rb +39 -0
- data/lib/rails/metro/packs/action_text_pack.rb +29 -0
- data/lib/rails/metro/packs/activeadmin_pack.rb +32 -0
- data/lib/rails/metro/packs/activity_feed_pack.rb +31 -0
- data/lib/rails/metro/packs/acts_as_list_pack.rb +28 -0
- data/lib/rails/metro/packs/acts_as_votable_pack.rb +32 -0
- data/lib/rails/metro/packs/administrate_pack.rb +31 -0
- data/lib/rails/metro/packs/after_party_pack.rb +31 -0
- data/lib/rails/metro/packs/ahoy_pack.rb +31 -0
- data/lib/rails/metro/packs/amplitude_pack.rb +45 -0
- data/lib/rails/metro/packs/annotate_pack.rb +30 -0
- data/lib/rails/metro/packs/api_cors_pack.rb +41 -0
- data/lib/rails/metro/packs/api_docs_pack.rb +34 -0
- data/lib/rails/metro/packs/api_guard_pack.rb +31 -0
- data/lib/rails/metro/packs/api_serialization_pack.rb +38 -0
- data/lib/rails/metro/packs/app_linting_pack.rb +35 -0
- data/lib/rails/metro/packs/audit_trail_pack.rb +31 -0
- data/lib/rails/metro/packs/authentication_pack.rb +31 -0
- data/lib/rails/metro/packs/authorization_pack.rb +31 -0
- data/lib/rails/metro/packs/avo_pack.rb +32 -0
- data/lib/rails/metro/packs/aws_ses_pack.rb +45 -0
- data/lib/rails/metro/packs/background_jobs_pack.rb +34 -0
- data/lib/rails/metro/packs/blazer_pack.rb +62 -0
- data/lib/rails/metro/packs/breadcrumbs_pack.rb +31 -0
- data/lib/rails/metro/packs/caching_pack.rb +30 -0
- data/lib/rails/metro/packs/charting_pack.rb +67 -0
- data/lib/rails/metro/packs/circuit_breaker_pack.rb +34 -0
- data/lib/rails/metro/packs/clicky_pack.rb +37 -0
- data/lib/rails/metro/packs/cloudinary_pack.rb +42 -0
- data/lib/rails/metro/packs/components_pack.rb +30 -0
- data/lib/rails/metro/packs/counter_culture_pack.rb +29 -0
- data/lib/rails/metro/packs/data_migrate_pack.rb +29 -0
- data/lib/rails/metro/packs/datadog_pack.rb +41 -0
- data/lib/rails/metro/packs/deployment_pack.rb +30 -0
- data/lib/rails/metro/packs/devise_pack.rb +33 -0
- data/lib/rails/metro/packs/doorkeeper_pack.rb +32 -0
- data/lib/rails/metro/packs/dotenv_pack.rb +36 -0
- data/lib/rails/metro/packs/elasticsearch_pack.rb +31 -0
- data/lib/rails/metro/packs/encryption_pack.rb +37 -0
- data/lib/rails/metro/packs/error_tracking_pack.rb +40 -0
- data/lib/rails/metro/packs/event_sourcing_pack.rb +31 -0
- data/lib/rails/metro/packs/faraday_pack.rb +42 -0
- data/lib/rails/metro/packs/fathom_pack.rb +36 -0
- data/lib/rails/metro/packs/feature_flags_pack.rb +34 -0
- data/lib/rails/metro/packs/friendly_id_pack.rb +31 -0
- data/lib/rails/metro/packs/geocoder_pack.rb +38 -0
- data/lib/rails/metro/packs/good_job_pack.rb +34 -0
- data/lib/rails/metro/packs/google_analytics_pack.rb +42 -0
- data/lib/rails/metro/packs/google_tag_manager_pack.rb +51 -0
- data/lib/rails/metro/packs/graphql_pack.rb +31 -0
- data/lib/rails/metro/packs/health_check_pack.rb +34 -0
- data/lib/rails/metro/packs/heap_pack.rb +39 -0
- data/lib/rails/metro/packs/honeybadger_pack.rb +37 -0
- data/lib/rails/metro/packs/hotwire_livereload_pack.rb +28 -0
- data/lib/rails/metro/packs/icons_pack.rb +28 -0
- data/lib/rails/metro/packs/invisible_captcha_pack.rb +35 -0
- data/lib/rails/metro/packs/kredis_pack.rb +31 -0
- data/lib/rails/metro/packs/lemon_squeezy_pack.rb +36 -0
- data/lib/rails/metro/packs/letter_opener_pack.rb +31 -0
- data/lib/rails/metro/packs/letter_opener_web_pack.rb +32 -0
- data/lib/rails/metro/packs/logging_pack.rb +36 -0
- data/lib/rails/metro/packs/madmin_pack.rb +32 -0
- data/lib/rails/metro/packs/mailgun_pack.rb +44 -0
- data/lib/rails/metro/packs/maintenance_mode_pack.rb +30 -0
- data/lib/rails/metro/packs/maintenance_tasks_pack.rb +32 -0
- data/lib/rails/metro/packs/markdown_pack.rb +48 -0
- data/lib/rails/metro/packs/matomo_pack.rb +48 -0
- data/lib/rails/metro/packs/meilisearch_pack.rb +37 -0
- data/lib/rails/metro/packs/mixpanel_pack.rb +47 -0
- data/lib/rails/metro/packs/mobility_pack.rb +32 -0
- data/lib/rails/metro/packs/mollie_pack.rb +36 -0
- data/lib/rails/metro/packs/multitenancy_pack.rb +35 -0
- data/lib/rails/metro/packs/newrelic_pack.rb +52 -0
- data/lib/rails/metro/packs/notifications_pack.rb +31 -0
- data/lib/rails/metro/packs/omniauth_pack.rb +49 -0
- data/lib/rails/metro/packs/paddle_pack.rb +37 -0
- data/lib/rails/metro/packs/pagination_pack.rb +44 -0
- data/lib/rails/metro/packs/passwordless_pack.rb +32 -0
- data/lib/rails/metro/packs/payments_pack.rb +35 -0
- data/lib/rails/metro/packs/paypal_pack.rb +35 -0
- data/lib/rails/metro/packs/pdf_pack.rb +45 -0
- data/lib/rails/metro/packs/performance_pack.rb +37 -0
- data/lib/rails/metro/packs/pghero_pack.rb +31 -0
- data/lib/rails/metro/packs/plausible_pack.rb +36 -0
- data/lib/rails/metro/packs/posthog_pack.rb +40 -0
- data/lib/rails/metro/packs/postmark_pack.rb +39 -0
- data/lib/rails/metro/packs/pretender_pack.rb +33 -0
- data/lib/rails/metro/packs/profiling_pack.rb +30 -0
- data/lib/rails/metro/packs/pundit_pack.rb +50 -0
- data/lib/rails/metro/packs/qr_code_pack.rb +37 -0
- data/lib/rails/metro/packs/r2_storage_pack.rb +48 -0
- data/lib/rails/metro/packs/rack_timeout_pack.rb +34 -0
- data/lib/rails/metro/packs/rails_i18n_pack.rb +31 -0
- data/lib/rails/metro/packs/ransack_pack.rb +29 -0
- data/lib/rails/metro/packs/rate_limiting_pack.rb +39 -0
- data/lib/rails/metro/packs/recaptcha_pack.rb +38 -0
- data/lib/rails/metro/packs/resend_pack.rb +37 -0
- data/lib/rails/metro/packs/revenuecat_pack.rb +36 -0
- data/lib/rails/metro/packs/rolify_pack.rb +32 -0
- data/lib/rails/metro/packs/rollbar_pack.rb +38 -0
- data/lib/rails/metro/packs/s3_storage_pack.rb +45 -0
- data/lib/rails/metro/packs/scenic_pack.rb +28 -0
- data/lib/rails/metro/packs/scheduling_pack.rb +46 -0
- data/lib/rails/metro/packs/search_pack.rb +32 -0
- data/lib/rails/metro/packs/security_pack.rb +30 -0
- data/lib/rails/metro/packs/sendgrid_pack.rb +44 -0
- data/lib/rails/metro/packs/sent_dm_pack.rb +36 -0
- data/lib/rails/metro/packs/seo_pack.rb +40 -0
- data/lib/rails/metro/packs/shoulda_matchers_pack.rb +37 -0
- data/lib/rails/metro/packs/sidekiq_pack.rb +42 -0
- data/lib/rails/metro/packs/simple_calendar_pack.rb +29 -0
- data/lib/rails/metro/packs/simple_form_pack.rb +30 -0
- data/lib/rails/metro/packs/simplecov_pack.rb +38 -0
- data/lib/rails/metro/packs/slack_notifier_pack.rb +36 -0
- data/lib/rails/metro/packs/soft_deletes_pack.rb +30 -0
- data/lib/rails/metro/packs/solidus_pack.rb +31 -0
- data/lib/rails/metro/packs/spreadsheets_pack.rb +29 -0
- data/lib/rails/metro/packs/statcounter_pack.rb +41 -0
- data/lib/rails/metro/packs/stimulus_components_pack.rb +33 -0
- data/lib/rails/metro/packs/storage_validations_pack.rb +28 -0
- data/lib/rails/metro/packs/strong_migrations_pack.rb +30 -0
- data/lib/rails/metro/packs/tagging_pack.rb +31 -0
- data/lib/rails/metro/packs/test_mocking_pack.rb +41 -0
- data/lib/rails/metro/packs/testing_pack.rb +39 -0
- data/lib/rails/metro/packs/twilio_pack.rb +38 -0
- data/lib/rails/metro/packs/vite_rails_pack.rb +31 -0
- data/lib/rails/metro/packs/web_push_pack.rb +39 -0
- data/lib/rails/metro/packs/webhooks_pack.rb +45 -0
- data/lib/rails/metro/packs/websockets_pack.rb +29 -0
- data/lib/rails/metro/template_compiler.rb +85 -0
- data/lib/rails/metro/tui/app.rb +119 -0
- data/lib/rails/metro/tui/steps/app_name_step.rb +57 -0
- data/lib/rails/metro/tui/steps/database_step.rb +53 -0
- data/lib/rails/metro/tui/steps/pack_step.rb +248 -0
- data/lib/rails/metro/tui/steps/review_step.rb +94 -0
- data/lib/rails/metro/tui/styles.rb +47 -0
- data/lib/rails/metro/tui.rb +37 -0
- data/lib/rails/metro/version.rb +5 -0
- data/lib/rails/metro.rb +9 -0
- metadata +206 -0
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
module Rails
|
|
2
|
+
module Metro
|
|
3
|
+
module Packs
|
|
4
|
+
class PostmarkPack < FeaturePack
|
|
5
|
+
pack_name "postmark"
|
|
6
|
+
description "Postmark for fast transactional email (99%+ inbox delivery)"
|
|
7
|
+
category "notifications"
|
|
8
|
+
|
|
9
|
+
def gems
|
|
10
|
+
[
|
|
11
|
+
{name: "postmark-rails"}
|
|
12
|
+
]
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def template_lines
|
|
16
|
+
[
|
|
17
|
+
'create_file "config/initializers/postmark.rb", <<~RUBY',
|
|
18
|
+
" ActionMailer::Base.delivery_method = :postmark",
|
|
19
|
+
" ActionMailer::Base.postmark_settings = {",
|
|
20
|
+
' api_token: Rails.application.credentials.dig(:postmark, :api_token) || ENV["POSTMARK_API_TOKEN"]',
|
|
21
|
+
" }",
|
|
22
|
+
"RUBY",
|
|
23
|
+
"",
|
|
24
|
+
'environment "config.action_mailer.delivery_method = :postmark", env: "production"'
|
|
25
|
+
]
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def post_install_notes
|
|
29
|
+
[
|
|
30
|
+
"Postmark: Add your API token with `bin/rails credentials:edit`:",
|
|
31
|
+
" postmark:",
|
|
32
|
+
" api_token: your_server_api_token",
|
|
33
|
+
"Postmark: Known for excellent deliverability and fast delivery times"
|
|
34
|
+
]
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
module Rails
|
|
2
|
+
module Metro
|
|
3
|
+
module Packs
|
|
4
|
+
class PretenderPack < FeaturePack
|
|
5
|
+
pack_name "pretender"
|
|
6
|
+
description "Pretender for user impersonation (admin support tool)"
|
|
7
|
+
category "ops"
|
|
8
|
+
|
|
9
|
+
def gems
|
|
10
|
+
[
|
|
11
|
+
{name: "pretender"}
|
|
12
|
+
]
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def template_lines
|
|
16
|
+
[
|
|
17
|
+
'inject_into_file "app/controllers/application_controller.rb", after: "class ApplicationController < ActionController::Base\\n" do',
|
|
18
|
+
' " impersonates :user\\n"',
|
|
19
|
+
"end"
|
|
20
|
+
]
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def post_install_notes
|
|
24
|
+
[
|
|
25
|
+
"Pretender: Impersonate with `impersonate_user(user)` in a controller action",
|
|
26
|
+
"Pretender: Stop with `stop_impersonating_user`",
|
|
27
|
+
"Pretender: `true_user` returns the admin, `current_user` returns the impersonated user"
|
|
28
|
+
]
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
module Rails
|
|
2
|
+
module Metro
|
|
3
|
+
module Packs
|
|
4
|
+
class ProfilingPack < FeaturePack
|
|
5
|
+
pack_name "profiling"
|
|
6
|
+
description "Stackprof + memory_profiler for CPU and memory profiling"
|
|
7
|
+
category "ops"
|
|
8
|
+
|
|
9
|
+
def gems
|
|
10
|
+
[
|
|
11
|
+
{name: "stackprof", group: :development},
|
|
12
|
+
{name: "memory_profiler", group: :development}
|
|
13
|
+
]
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def template_lines
|
|
17
|
+
[]
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def post_install_notes
|
|
21
|
+
[
|
|
22
|
+
"Profiling: CPU profile with `StackProf.run(mode: :cpu) { code }` and `StackProf::Report`",
|
|
23
|
+
"Profiling: Memory profile with `MemoryProfiler.report { code }.pretty_print`",
|
|
24
|
+
"Profiling: Both available in development only"
|
|
25
|
+
]
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
module Rails
|
|
2
|
+
module Metro
|
|
3
|
+
module Packs
|
|
4
|
+
class PunditPack < FeaturePack
|
|
5
|
+
pack_name "pundit"
|
|
6
|
+
description "Pundit for simple, policy-based authorization"
|
|
7
|
+
category "core"
|
|
8
|
+
conflicts_with "authorization"
|
|
9
|
+
|
|
10
|
+
def gems
|
|
11
|
+
[
|
|
12
|
+
{name: "pundit"}
|
|
13
|
+
]
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def template_lines
|
|
17
|
+
[
|
|
18
|
+
'inject_into_file "app/controllers/application_controller.rb", after: "class ApplicationController < ActionController::Base\\n" do',
|
|
19
|
+
' " include Pundit::Authorization\\n"',
|
|
20
|
+
"end",
|
|
21
|
+
"",
|
|
22
|
+
'create_file "app/policies/application_policy.rb", <<~RUBY',
|
|
23
|
+
" class ApplicationPolicy",
|
|
24
|
+
" attr_reader :user, :record",
|
|
25
|
+
"",
|
|
26
|
+
" def initialize(user, record)",
|
|
27
|
+
" @user = user",
|
|
28
|
+
" @record = record",
|
|
29
|
+
" end",
|
|
30
|
+
"",
|
|
31
|
+
" def index? = false",
|
|
32
|
+
" def show? = false",
|
|
33
|
+
" def create? = false",
|
|
34
|
+
" def update? = false",
|
|
35
|
+
" def destroy? = false",
|
|
36
|
+
" end",
|
|
37
|
+
"RUBY"
|
|
38
|
+
]
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def post_install_notes
|
|
42
|
+
[
|
|
43
|
+
"Pundit: Generate policies with `bin/rails g pundit:policy User`",
|
|
44
|
+
"Pundit: Use `authorize @user` in controllers"
|
|
45
|
+
]
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
module Rails
|
|
2
|
+
module Metro
|
|
3
|
+
module Packs
|
|
4
|
+
class QrCodePack < FeaturePack
|
|
5
|
+
pack_name "qr_code"
|
|
6
|
+
description "RQRCode for QR code generation (SVG, PNG, ANSI)"
|
|
7
|
+
category "ui"
|
|
8
|
+
|
|
9
|
+
def gems
|
|
10
|
+
[
|
|
11
|
+
{name: "rqrcode"}
|
|
12
|
+
]
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def template_lines
|
|
16
|
+
[
|
|
17
|
+
'create_file "app/helpers/qr_code_helper.rb", <<~RUBY',
|
|
18
|
+
" module QrCodeHelper",
|
|
19
|
+
' def qr_code_svg(content, size: 4, color: "000")',
|
|
20
|
+
" qr = RQRCode::QRCode.new(content)",
|
|
21
|
+
' qr.as_svg(module_size: size, color: color, shape_rendering: "crispEdges").html_safe',
|
|
22
|
+
" end",
|
|
23
|
+
" end",
|
|
24
|
+
"RUBY"
|
|
25
|
+
]
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def post_install_notes
|
|
29
|
+
[
|
|
30
|
+
"QR Code: Use `<%= qr_code_svg(\"https://example.com\") %>` in views",
|
|
31
|
+
"QR Code: Also supports PNG with `qr.as_png` and ANSI terminal output"
|
|
32
|
+
]
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
module Rails
|
|
2
|
+
module Metro
|
|
3
|
+
module Packs
|
|
4
|
+
class R2StoragePack < FeaturePack
|
|
5
|
+
pack_name "r2_storage"
|
|
6
|
+
description "Cloudflare R2 for S3-compatible Active Storage (no egress fees)"
|
|
7
|
+
category "core"
|
|
8
|
+
conflicts_with "s3_storage"
|
|
9
|
+
|
|
10
|
+
def gems
|
|
11
|
+
[
|
|
12
|
+
{name: "aws-sdk-s3"}
|
|
13
|
+
]
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def template_lines
|
|
17
|
+
[
|
|
18
|
+
'inject_into_file "config/storage.yml", <<~YML',
|
|
19
|
+
"",
|
|
20
|
+
" r2:",
|
|
21
|
+
" service: S3",
|
|
22
|
+
" endpoint: <%= Rails.application.credentials.dig(:r2, :endpoint) %>",
|
|
23
|
+
' region: <%= Rails.application.credentials.dig(:r2, :region) || "auto" %>',
|
|
24
|
+
" bucket: <%= Rails.application.credentials.dig(:r2, :bucket) %>",
|
|
25
|
+
" access_key_id: <%= Rails.application.credentials.dig(:r2, :access_key_id) %>",
|
|
26
|
+
" secret_access_key: <%= Rails.application.credentials.dig(:r2, :secret_access_key) %>",
|
|
27
|
+
"YML",
|
|
28
|
+
"",
|
|
29
|
+
'environment "config.active_storage.service = :r2", env: "production"'
|
|
30
|
+
]
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def post_install_notes
|
|
34
|
+
[
|
|
35
|
+
"R2: Add your Cloudflare credentials with `bin/rails credentials:edit`:",
|
|
36
|
+
" r2:",
|
|
37
|
+
" endpoint: https://ACCOUNT_ID.r2.cloudflarestorage.com",
|
|
38
|
+
" region: auto",
|
|
39
|
+
" bucket: your-bucket-name",
|
|
40
|
+
" access_key_id: your_access_key",
|
|
41
|
+
" secret_access_key: your_secret_key",
|
|
42
|
+
"R2: Zero egress fees -- great for media-heavy apps"
|
|
43
|
+
]
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
module Rails
|
|
2
|
+
module Metro
|
|
3
|
+
module Packs
|
|
4
|
+
class RackTimeoutPack < FeaturePack
|
|
5
|
+
pack_name "rack_timeout"
|
|
6
|
+
description "Rack::Timeout for request timeout protection"
|
|
7
|
+
category "ops"
|
|
8
|
+
|
|
9
|
+
def gems
|
|
10
|
+
[
|
|
11
|
+
{name: "rack-timeout"}
|
|
12
|
+
]
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def template_lines
|
|
16
|
+
[
|
|
17
|
+
'create_file "config/initializers/rack_timeout.rb", <<~RUBY',
|
|
18
|
+
" Rack::Timeout.service_timeout = 15",
|
|
19
|
+
" Rack::Timeout.wait_timeout = 30",
|
|
20
|
+
" Rack::Timeout.wait_overtime = 60",
|
|
21
|
+
"RUBY"
|
|
22
|
+
]
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def post_install_notes
|
|
26
|
+
[
|
|
27
|
+
"Rack::Timeout: Requests exceeding 15s are terminated with a Rack::Timeout::RequestTimeoutError",
|
|
28
|
+
"Rack::Timeout: Customize thresholds in config/initializers/rack_timeout.rb"
|
|
29
|
+
]
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
module Rails
|
|
2
|
+
module Metro
|
|
3
|
+
module Packs
|
|
4
|
+
class RailsI18nPack < FeaturePack
|
|
5
|
+
pack_name "rails_i18n"
|
|
6
|
+
description "Rails I18n locale data for 100+ languages"
|
|
7
|
+
category "core"
|
|
8
|
+
|
|
9
|
+
def gems
|
|
10
|
+
[
|
|
11
|
+
{name: "rails-i18n"}
|
|
12
|
+
]
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def template_lines
|
|
16
|
+
[
|
|
17
|
+
'environment "config.i18n.available_locales = [:en]',
|
|
18
|
+
' config.i18n.default_locale = :en"'
|
|
19
|
+
]
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def post_install_notes
|
|
23
|
+
[
|
|
24
|
+
"I18n: Add locales to config.i18n.available_locales as needed",
|
|
25
|
+
"I18n: Locale files available for 100+ languages (date formats, pluralization, etc.)"
|
|
26
|
+
]
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
module Rails
|
|
2
|
+
module Metro
|
|
3
|
+
module Packs
|
|
4
|
+
class RansackPack < FeaturePack
|
|
5
|
+
pack_name "ransack"
|
|
6
|
+
description "Ransack for object-based search and filter forms"
|
|
7
|
+
category "ui"
|
|
8
|
+
|
|
9
|
+
def gems
|
|
10
|
+
[
|
|
11
|
+
{name: "ransack", version: "~> 4.0"}
|
|
12
|
+
]
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def template_lines
|
|
16
|
+
[]
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def post_install_notes
|
|
20
|
+
[
|
|
21
|
+
"Ransack: Use `@q = User.ransack(params[:q])` in controllers",
|
|
22
|
+
"Ransack: Build forms with `search_form_for @q do |f|` in views",
|
|
23
|
+
"Ransack: Supports sorting, predicates (_cont, _eq, _gt, etc.)"
|
|
24
|
+
]
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
module Rails
|
|
2
|
+
module Metro
|
|
3
|
+
module Packs
|
|
4
|
+
class RateLimitingPack < FeaturePack
|
|
5
|
+
pack_name "rate_limiting"
|
|
6
|
+
description "Rack::Attack for throttling and blocking"
|
|
7
|
+
category "ops"
|
|
8
|
+
|
|
9
|
+
def gems
|
|
10
|
+
[
|
|
11
|
+
{name: "rack-attack"}
|
|
12
|
+
]
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def template_lines
|
|
16
|
+
[
|
|
17
|
+
'create_file "config/initializers/rack_attack.rb", <<~RUBY',
|
|
18
|
+
" class Rack::Attack",
|
|
19
|
+
' throttle("req/ip", limit: 300, period: 5.minutes) do |req|',
|
|
20
|
+
" req.ip",
|
|
21
|
+
" end",
|
|
22
|
+
"",
|
|
23
|
+
' throttle("logins/ip", limit: 5, period: 20.seconds) do |req|',
|
|
24
|
+
' req.ip if req.path == "/session" && req.post?',
|
|
25
|
+
" end",
|
|
26
|
+
" end",
|
|
27
|
+
"RUBY"
|
|
28
|
+
]
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def post_install_notes
|
|
32
|
+
[
|
|
33
|
+
"Rate Limiting: Customize throttle rules in config/initializers/rack_attack.rb"
|
|
34
|
+
]
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
module Rails
|
|
2
|
+
module Metro
|
|
3
|
+
module Packs
|
|
4
|
+
class RecaptchaPack < FeaturePack
|
|
5
|
+
pack_name "recaptcha"
|
|
6
|
+
description "reCAPTCHA v3 for Google-powered bot protection"
|
|
7
|
+
category "core"
|
|
8
|
+
|
|
9
|
+
def gems
|
|
10
|
+
[
|
|
11
|
+
{name: "recaptcha"}
|
|
12
|
+
]
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def template_lines
|
|
16
|
+
[
|
|
17
|
+
'create_file "config/initializers/recaptcha.rb", <<~RUBY',
|
|
18
|
+
" Recaptcha.configure do |config|",
|
|
19
|
+
' config.site_key = Rails.application.credentials.dig(:recaptcha, :site_key) || ENV["RECAPTCHA_SITE_KEY"]',
|
|
20
|
+
' config.secret_key = Rails.application.credentials.dig(:recaptcha, :secret_key) || ENV["RECAPTCHA_SECRET_KEY"]',
|
|
21
|
+
" end",
|
|
22
|
+
"RUBY"
|
|
23
|
+
]
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def post_install_notes
|
|
27
|
+
[
|
|
28
|
+
"reCAPTCHA: Add your keys with `bin/rails credentials:edit`:",
|
|
29
|
+
" recaptcha:",
|
|
30
|
+
" site_key: your_site_key",
|
|
31
|
+
" secret_key: your_secret_key",
|
|
32
|
+
"reCAPTCHA: Use `<%= recaptcha_v3 %>` in forms and `verify_recaptcha` in controllers"
|
|
33
|
+
]
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
module Rails
|
|
2
|
+
module Metro
|
|
3
|
+
module Packs
|
|
4
|
+
class ResendPack < FeaturePack
|
|
5
|
+
pack_name "resend"
|
|
6
|
+
description "Resend for transactional and marketing email delivery"
|
|
7
|
+
category "notifications"
|
|
8
|
+
|
|
9
|
+
def gems
|
|
10
|
+
[
|
|
11
|
+
{name: "resend"}
|
|
12
|
+
]
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def template_lines
|
|
16
|
+
[
|
|
17
|
+
'create_file "config/initializers/resend.rb", <<~RUBY',
|
|
18
|
+
" Resend.api_key = Rails.application.credentials.dig(:resend, :api_key) || ENV[\"RESEND_API_KEY\"]",
|
|
19
|
+
"RUBY",
|
|
20
|
+
"",
|
|
21
|
+
"# Configure Action Mailer to use Resend",
|
|
22
|
+
'environment "config.action_mailer.delivery_method = :resend", env: "production"'
|
|
23
|
+
]
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def post_install_notes
|
|
27
|
+
[
|
|
28
|
+
"Resend: Add your API key with `bin/rails credentials:edit`:",
|
|
29
|
+
" resend:",
|
|
30
|
+
" api_key: re_your_api_key_here",
|
|
31
|
+
"Resend: Verify your sending domain at https://resend.com/domains"
|
|
32
|
+
]
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
module Rails
|
|
2
|
+
module Metro
|
|
3
|
+
module Packs
|
|
4
|
+
class RevenuecatPack < FeaturePack
|
|
5
|
+
pack_name "revenuecat"
|
|
6
|
+
description "RevenueCat for subscription management and in-app purchases"
|
|
7
|
+
category "payments"
|
|
8
|
+
|
|
9
|
+
def gems
|
|
10
|
+
[
|
|
11
|
+
{name: "revenuecat-api"}
|
|
12
|
+
]
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def template_lines
|
|
16
|
+
[
|
|
17
|
+
'create_file "config/initializers/revenuecat.rb", <<~RUBY',
|
|
18
|
+
" RevenueCat.configure do |config|",
|
|
19
|
+
' config.api_key = Rails.application.credentials.dig(:revenuecat, :api_key) || ENV["REVENUECAT_API_KEY"]',
|
|
20
|
+
" end",
|
|
21
|
+
"RUBY"
|
|
22
|
+
]
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def post_install_notes
|
|
26
|
+
[
|
|
27
|
+
"RevenueCat: Add your API key with `bin/rails credentials:edit`:",
|
|
28
|
+
" revenuecat:",
|
|
29
|
+
" api_key: your_api_key_here",
|
|
30
|
+
"RevenueCat: Best suited for apps with mobile (iOS/Android) subscription billing"
|
|
31
|
+
]
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
module Rails
|
|
2
|
+
module Metro
|
|
3
|
+
module Packs
|
|
4
|
+
class RolifyPack < FeaturePack
|
|
5
|
+
pack_name "rolify"
|
|
6
|
+
description "Rolify for role management (admin, editor, viewer, etc.)"
|
|
7
|
+
category "core"
|
|
8
|
+
|
|
9
|
+
def gems
|
|
10
|
+
[
|
|
11
|
+
{name: "rolify"}
|
|
12
|
+
]
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def template_lines
|
|
16
|
+
[
|
|
17
|
+
'rails_command "generate rolify Role User"'
|
|
18
|
+
]
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def post_install_notes
|
|
22
|
+
[
|
|
23
|
+
"Rolify: Run `bin/rails db:migrate` to create roles table",
|
|
24
|
+
"Rolify: Assign with `user.add_role :admin`",
|
|
25
|
+
"Rolify: Check with `user.has_role? :admin`",
|
|
26
|
+
"Rolify: Pairs well with Pundit or Action Policy for authorization"
|
|
27
|
+
]
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
module Rails
|
|
2
|
+
module Metro
|
|
3
|
+
module Packs
|
|
4
|
+
class RollbarPack < FeaturePack
|
|
5
|
+
pack_name "rollbar"
|
|
6
|
+
description "Rollbar for real-time error tracking and debugging"
|
|
7
|
+
category "ops"
|
|
8
|
+
conflicts_with "error_tracking", "honeybadger"
|
|
9
|
+
|
|
10
|
+
def gems
|
|
11
|
+
[
|
|
12
|
+
{name: "rollbar"}
|
|
13
|
+
]
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def template_lines
|
|
17
|
+
[
|
|
18
|
+
'create_file "config/initializers/rollbar.rb", <<~RUBY',
|
|
19
|
+
" Rollbar.configure do |config|",
|
|
20
|
+
' config.access_token = Rails.application.credentials.dig(:rollbar, :access_token) || ENV["ROLLBAR_ACCESS_TOKEN"]',
|
|
21
|
+
" config.enabled = !Rails.env.test?",
|
|
22
|
+
" config.environment = Rails.env",
|
|
23
|
+
" end",
|
|
24
|
+
"RUBY"
|
|
25
|
+
]
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def post_install_notes
|
|
29
|
+
[
|
|
30
|
+
"Rollbar: Add your access token with `bin/rails credentials:edit`:",
|
|
31
|
+
" rollbar:",
|
|
32
|
+
" access_token: your_token_here"
|
|
33
|
+
]
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
module Rails
|
|
2
|
+
module Metro
|
|
3
|
+
module Packs
|
|
4
|
+
class S3StoragePack < FeaturePack
|
|
5
|
+
pack_name "s3_storage"
|
|
6
|
+
description "AWS S3 for Active Storage file uploads"
|
|
7
|
+
category "core"
|
|
8
|
+
conflicts_with "r2_storage"
|
|
9
|
+
|
|
10
|
+
def gems
|
|
11
|
+
[
|
|
12
|
+
{name: "aws-sdk-s3"}
|
|
13
|
+
]
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def template_lines
|
|
17
|
+
[
|
|
18
|
+
'inject_into_file "config/storage.yml", <<~YML',
|
|
19
|
+
"",
|
|
20
|
+
" amazon:",
|
|
21
|
+
" service: S3",
|
|
22
|
+
" access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %>",
|
|
23
|
+
" secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %>",
|
|
24
|
+
' region: <%= Rails.application.credentials.dig(:aws, :region) || "us-east-1" %>',
|
|
25
|
+
" bucket: <%= Rails.application.credentials.dig(:aws, :bucket) %>",
|
|
26
|
+
"YML",
|
|
27
|
+
"",
|
|
28
|
+
'environment "config.active_storage.service = :amazon", env: "production"'
|
|
29
|
+
]
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def post_install_notes
|
|
33
|
+
[
|
|
34
|
+
"S3: Add your AWS credentials with `bin/rails credentials:edit`:",
|
|
35
|
+
" aws:",
|
|
36
|
+
" access_key_id: AKIA...",
|
|
37
|
+
" secret_access_key: your_secret",
|
|
38
|
+
" region: us-east-1",
|
|
39
|
+
" bucket: your-bucket-name"
|
|
40
|
+
]
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
module Rails
|
|
2
|
+
module Metro
|
|
3
|
+
module Packs
|
|
4
|
+
class ScenicPack < FeaturePack
|
|
5
|
+
pack_name "scenic"
|
|
6
|
+
description "Scenic for versioned database views"
|
|
7
|
+
category "data"
|
|
8
|
+
|
|
9
|
+
def gems
|
|
10
|
+
[
|
|
11
|
+
{name: "scenic"}
|
|
12
|
+
]
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def template_lines
|
|
16
|
+
[]
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def post_install_notes
|
|
20
|
+
[
|
|
21
|
+
"Scenic: Generate views with `bin/rails g scenic:view search_results`",
|
|
22
|
+
"Scenic: Views are versioned -- update with `bin/rails g scenic:view search_results --replace`"
|
|
23
|
+
]
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
module Rails
|
|
2
|
+
module Metro
|
|
3
|
+
module Packs
|
|
4
|
+
class SchedulingPack < FeaturePack
|
|
5
|
+
pack_name "scheduling"
|
|
6
|
+
description "Recurring tasks with Solid Queue and solid_queue recurring"
|
|
7
|
+
category "core"
|
|
8
|
+
depends_on "background_jobs"
|
|
9
|
+
|
|
10
|
+
def gems
|
|
11
|
+
[]
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def template_lines
|
|
15
|
+
[
|
|
16
|
+
'create_file "config/recurring.yml", <<~YML',
|
|
17
|
+
" production:",
|
|
18
|
+
" cleanup_old_records:",
|
|
19
|
+
" class: CleanupOldRecordsJob",
|
|
20
|
+
' schedule: "every day at 3am"',
|
|
21
|
+
" queue: default",
|
|
22
|
+
"YML",
|
|
23
|
+
"",
|
|
24
|
+
'create_file "app/jobs/cleanup_old_records_job.rb", <<~RUBY',
|
|
25
|
+
" class CleanupOldRecordsJob < ApplicationJob",
|
|
26
|
+
" queue_as :default",
|
|
27
|
+
"",
|
|
28
|
+
" def perform",
|
|
29
|
+
" # Add your recurring cleanup logic here",
|
|
30
|
+
' Rails.logger.info "Running scheduled cleanup"',
|
|
31
|
+
" end",
|
|
32
|
+
" end",
|
|
33
|
+
"RUBY"
|
|
34
|
+
]
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def post_install_notes
|
|
38
|
+
[
|
|
39
|
+
"Scheduling: Define recurring jobs in config/recurring.yml",
|
|
40
|
+
"Scheduling: Solid Queue handles scheduling natively -- no cron or external gems needed"
|
|
41
|
+
]
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|