mat_views (engine)
Rails engine that manages PostgreSQL materialized views with definitions, services, background jobs, and Rake tasks.
Quickstart (diagram)
flowchart LR
A[Define MatViewDefinition] --> B[Create]
B --> C[Unique Index for CONCURRENT]
C --> D[Refresh: regular or concurrent or swap]
D --> E[Read MV]
D --> F[Track runs]
Install
bundle add mat_views
bin/rails g mat_views:install
bin/rails db:migrate
# config/initializers/mat_views.rb
MatViews.configure do |c|
c.job_queue = :default
end
Define a view
defn = MatViews::MatViewDefinition.create!(
name: 'mv_user_activity',
sql: <<~SQL,
SELECT u.id AS user_id,
COUNT(a.*) AS accounts_count,
COUNT(e.*) AS events_count,
COUNT(s.*) AS sessions_count
FROM users u
LEFT JOIN accounts a ON a.user_id = u.id
LEFT JOIN events e ON e.user_id = u.id
LEFT JOIN sessions s ON s.user_id = u.id
GROUP BY u.id
SQL
refresh_strategy: :concurrent,
unique_index_columns: ['user_id']
)
Services & Jobs
# Create
MatViews::Services::CreateView.new(defn, force: true).call
MatViews::CreateViewJob.perform_later(defn.id, force: true)
# Refresh
MatViews::Services::RegularRefresh.new(defn, row_count_strategy: :estimated).call
MatViews::RefreshViewJob.perform_later(defn.id, row_count_strategy: :exact)
# Delete
MatViews::Services::DeleteView.new(defn, cascade: false, if_exists: true).call
MatViews::DeleteViewJob.perform_later(defn.id, cascade: true)
Uniform response: status, meta, success? / error?.
Enqueue adapter
MatViews::Jobs::Adapter.enqueue(job_class, queue: :default, args: [...])
- Uses your configured backend; no guessing.
- Supports ActiveJob, Sidekiq, Resque.
Rake tasks
# Create
bundle exec rake mat_views:create_by_name\[VIEW_NAME,force,row_count_strategy,--yes]
bundle exec rake mat_views:create_by_id\[ID,force,row_count_strategy,--yes]
bundle exec rake mat_views:create_all\[force,row_count_strategy,--yes]
# Refresh
bundle exec rake mat_views:refresh_by_name\[VIEW_NAME,row_count_strategy,--yes]
bundle exec rake mat_views:refresh_by_id\[ID,row_count_strategy,--yes]
bundle exec rake mat_views:refresh_all\[row_count_strategy,--yes]
# Delete
bundle exec rake mat_views:delete_by_name\[VIEW_NAME,cascade,row_count_strategy,--yes]
bundle exec rake mat_views:delete_by_id\[ID,cascade,row_count_strategy,--yes]
bundle exec rake mat_views:delete_all\[cascade,row_count_strategy,--yes]
Docs & policies
- Root README: ../README.md
- Contributing: ../CONTRIBUTING.md
- Security policy: ../SECURITY.md
- Code of Conduct: ../CODE_OF_CONDUCT.md