### Generate Scenic View Migration and SQL File Source: https://github.com/scenic-views/scenic/blob/main/README.md Use this command to create a new migration and an associated SQL file for defining a database view. The SQL file should contain the view's definition. ```sh $ rails generate scenic:view search_results create db/views/search_results_v01.sql create db/migrate/[TIMESTAMP]_create_search_results.rb ``` -------------------------------- ### Configure Scenic Database Adapter Source: https://context7.com/scenic-views/scenic/llms.txt Use `Scenic.configure` to override the default PostgreSQL adapter with a custom one that implements the `Scenic::Adapters::Postgres` interface. ```ruby # config/initializers/scenic.rb ``` -------------------------------- ### Generate a New View Source: https://context7.com/scenic-views/scenic/llms.txt Use the `scenic:view` generator to create a versioned SQL definition file and its corresponding migration. Running it again on an existing view increments the version. ```bash # Create version 1 of a new view $ rails generate scenic:view search_results # create db/views/search_results_v01.sql # create db/migrate/20240101000000_create_search_results.rb ``` ```bash # Update to version 2 (copies v01 content into v02 automatically) $ rails generate scenic:view search_results # create db/views/search_results_v02.sql # create db/migrate/20240102000000_update_search_results_to_version_2.rb ``` ```bash # Create a materialized view $ rails generate scenic:view daily_stats --materialized # create db/views/daily_stats_v01.sql # create db/migrate/20240103000000_create_daily_stats.rb ``` ```bash # Update a materialized view using side-by-side strategy (minimizes lock time) $ rails generate scenic:view daily_stats --materialized --side-by-side # create db/views/daily_stats_v02.sql # create db/migrate/20240104000000_update_daily_stats_to_version_2.rb ``` ```bash # Update a view using CREATE OR REPLACE VIEW instead of drop-and-recreate $ rails generate scenic:view search_results --replace # create db/views/search_results_v03.sql # create db/migrate/20240105000000_update_search_results_to_version_3.rb ``` -------------------------------- ### Migrate Database to Create View Source: https://github.com/scenic-views/scenic/blob/main/README.md Execute this rake command to apply the generated migration and create the database view defined in the SQL file. ```sh $ rake db:migrate ``` -------------------------------- ### Configure Scenic Database Adapter Source: https://context7.com/scenic-views/scenic/llms.txt Configure Scenic to use the default Postgres adapter, a custom connectable object, or a third-party adapter like MySQL. ```ruby Scenic.configure do |config| config.database = Scenic::Adapters::Postgres.new end ``` ```ruby Scenic.configure do |config| config.database = Scenic::Adapters::Postgres.new(MyApp::ReadReplica) end ``` ```ruby require "scenic/adapters/mysql" Scenic.configure do |config| config.database = Scenic::Adapters::MySQL.new end ``` -------------------------------- ### Generate Migration to Update Scenic View Source: https://github.com/scenic-views/scenic/blob/main/README.md Run this command again to create a new version of the view definition and a migration to update it. Scenic automatically handles versioning. ```sh $ rails generate scenic:view search_results create db/views/search_results_v02.sql create db/migrate/[TIMESTAMP]_update_search_results_to_version_2.rb ``` -------------------------------- ### create_view Source: https://context7.com/scenic-views/scenic/llms.txt Creates a new database view. Can be a standard view or a materialized view, and can be defined with inline SQL or from a SQL file. ```APIDOC ## Migration method: `create_view` — Create a new view Creates a new database view. Can be a standard view or a materialized view, and can be defined with inline SQL or from a SQL file. ```ruby class CreateSearchResults < ActiveRecord::Migration[7.1] def change # From db/views/search_results_v01.sql create_view :search_results # Explicitly specify version create_view :search_results, version: 1 # Inline SQL (mutually exclusive with version:) create_view :active_users, sql_definition: <<-SQL SELECT * FROM users WHERE active = true SQL # Materialized view from db/views/daily_stats_v01.sql create_view :daily_stats, version: 1, materialized: true # Materialized view created without data (must be refreshed before use) create_view :heavy_report, version: 1, materialized: { no_data: true } end end ``` ``` -------------------------------- ### Create View Migration Method Source: https://context7.com/scenic-views/scenic/llms.txt Use the `create_view` method within migrations to define database views from SQL files or inline strings. Supports materialized views and options for initial data loading. ```ruby # db/views/search_results_v01.sql content: # SELECT statuses.id AS searchable_id, 'Status' AS searchable_type, # comments.body AS term # FROM statuses # JOIN comments ON statuses.id = comments.status_id # UNION ``` -------------------------------- ### Generate Migration to Replace Scenic View Source: https://github.com/scenic-views/scenic/blob/main/README.md Use the --replace option to generate a migration that uses 'CREATE OR REPLACE VIEW' SQL, updating the view in place without dropping it. This is useful for views with complex dependencies. ```sh $ rails generate scenic:view search_results --replace create db/views/search_results_v02.sql create db/migrate/[TIMESTAMP]_update_search_results_to_version_2.rb ``` -------------------------------- ### Create Database Views in Rails Migrations Source: https://context7.com/scenic-views/scenic/llms.txt Use `create_view` to define new database views. You can specify a version, use inline SQL, or create materialized views. ```ruby create_view :search_results ``` ```ruby create_view :search_results, version: 1 ``` ```ruby create_view :active_users, sql_definition: <<-SQL SELECT * FROM users WHERE active = true SQL ``` ```ruby create_view :daily_stats, version: 1, materialized: true ``` ```ruby create_view :heavy_report, version: 1, materialized: { no_data: true } ``` -------------------------------- ### Generate a View-Backed Model Source: https://context7.com/scenic-views/scenic/llms.txt Use the `scenic:model` generator to create a view-backed model, including the model class, test files, and fixtures. For materialized views, it automatically adds `refresh` and `populated?` methods. ```bash # Generate a standard view-backed model $ rails generate scenic:model search_result # invoke active_record # create app/models/search_result.rb # invoke test_unit # create test/models/search_result_test.rb # create test/fixtures/search_results.yml # create db/views/search_results_v01.sql # create db/migrate/20240101000000_create_search_results.rb ``` ```bash # Generate a materialized view-backed model $ rails generate scenic:model recent_order --materialized # create app/models/recent_order.rb (includes .refresh and .populated? methods) # create db/views/recent_orders_v01.sql # create db/migrate/20240101000000_create_recent_orders.rb ``` -------------------------------- ### Generate a Materialized View with Side-by-Side Update Strategy Source: https://github.com/scenic-views/scenic/blob/main/README.md Use the `--side-by-side` option with the `scenic:view` generator to create a migration that updates materialized views with minimal downtime. This strategy prepares the new version under a temporary name before replacing the original. ```sh $ rails generate scenic:view search_results --materialized --side-by-side create db/views/search_results_v02.sql create db/migrate/[TIMESTAMP]_update_search_results_to_version_2.rb ``` -------------------------------- ### Generate a Scenic Model Source: https://github.com/scenic-views/scenic/blob/main/README.md Use the `scenic:model` generator to create a model backed by a database view. This generator is a superset of `scenic:view` and creates a Scenic view migration instead of a table migration. ```sh $ rails generate scenic:model recent_status invoke active_record create app/models/recent_status.rb invoke test_unit create test/models/recent_status_test.rb create test/fixtures/recent_statuses.yml create db/views/recent_statuses_v01.sql create db/migrate/20151112015036_create_recent_statuses.rb ``` -------------------------------- ### Materialized View Model Methods Source: https://context7.com/scenic-views/scenic/llms.txt Models backed by materialized views automatically include `refresh` and `populated?` methods for managing the view's data. ```ruby # app/models/recent_order.rb class RecentOrder < ApplicationRecord def self.refresh Scenic.database.refresh_materialized_view(table_name, concurrently: false, cascade: false) end def self.populated? Scenic.database.populated?(table_name) end end ``` -------------------------------- ### Add Scenic Gem to Gemfile Source: https://context7.com/scenic-views/scenic/llms.txt Add the Scenic gem to your application's Gemfile to begin using its features. ```ruby # Gemfile gem "scenic" ``` -------------------------------- ### Define a View-Backed ActiveRecord Model Source: https://context7.com/scenic-views/scenic/llms.txt Define a model backed by a SQL view. Declare `primary_key` if you need `find`, `first`, or `last`. Mark the model `readonly` to prevent save attempts. ```sql -- db/views/search_results_v01.sql -- SELECT -- statuses.id AS searchable_id, -- 'Status' AS searchable_type, -- comments.body AS term -- FROM statuses -- JOIN comments ON statuses.id = comments.status_id -- UNION -- SELECT statuses.id, 'Status', statuses.body FROM statuses ``` ```ruby class SearchResult < ApplicationRecord # Required for find / first / last self.primary_key = :searchable_id belongs_to :searchable, polymorphic: true # Prevent ActiveRecord from calling INSERT/UPDATE/DELETE def readonly? true end end ``` ```ruby # Usage SearchResult.where(searchable_type: "Status").limit(10).each do |result| puts result.term end SearchResult.find(42) # uses searchable_id as PK SearchResult.first # ORDER BY searchable_id ASC LIMIT 1 ``` -------------------------------- ### Define a Model Backed by a Database View Source: https://github.com/scenic-views/scenic/blob/main/README.md Use this when integrating a database view with an ActiveRecord model. Declare the primary key if `find` operations are needed and set `readonly?` to true to prevent accidental saves. ```ruby class SearchResult < ApplicationRecord belongs_to :searchable, polymorphic: true # If you want to be able to call +Model.find+, # you must declare the primary key. It can not be # inferred from column information. # self.primary_key = :id # this isn't strictly necessary, but it will prevent # rails from calling save, which would fail anyway. def readonly? true end end ``` -------------------------------- ### Schema Dumping with Scenic Views Source: https://context7.com/scenic-views/scenic/llms.txt Scenic automatically includes views and their indexes in `schema.rb` for `rake db:schema:load` compatibility. ```ruby # Example output in db/schema.rb after running migrations: ActiveRecord::Schema[7.1].define(version: 2024_01_01_000001) do # ... regular tables ... create_view "search_results", sql_definition: <<-SQL SELECT statuses.id AS searchable_id, 'Status'::text AS searchable_type, comments.body AS term FROM statuses JOIN comments ON statuses.id = comments.status_id UNION SELECT statuses.id, 'Status'::text, statuses.body FROM statuses SQL create_view "daily_stats", materialized: true, sql_definition: <<-SQL SELECT date_trunc('day', created_at) AS day, COUNT(*) AS order_count, SUM(total_cents) AS revenue_cents FROM orders GROUP BY 1 SQL add_index "daily_stats", ["day"], name: "index_daily_stats_on_day", unique: true end ``` -------------------------------- ### replace_view Source: https://context7.com/scenic-views/scenic/llms.txt Replaces a view in place using `CREATE OR REPLACE VIEW`. This is useful for maintaining dependent views and has restrictions on adding/removing/reordering columns. Only supports non-materialized views. ```APIDOC ## Migration method: `replace_view` — Replace a view in place Uses `CREATE OR REPLACE VIEW` instead of drop-and-recreate. Useful when views have complex dependency hierarchies. Only supports non-materialized views. New columns may only be added at the end; existing columns cannot be removed or reordered. ```ruby class UpdateSearchResultsToVersion2 < ActiveRecord::Migration[7.1] def change # Uses CREATE OR REPLACE VIEW — retains all dependent views replace_view :search_results, version: 2, revert_to_version: 1 end end ``` ``` -------------------------------- ### Update Materialized View using Side-by-Side Strategy Source: https://github.com/scenic-views/scenic/blob/main/README.md This migration defines how to update a materialized view using the `side_by_side` strategy. It specifies the new version, the version to revert to, and the materialized view options. ```ruby class UpdateSearchResultsToVersion2 < ActiveRecord::Migration def change update_view :search_results, version: 2, revert_to_version: 1, materialized: { side_by_side: true } end end ``` -------------------------------- ### drop_view Source: https://context7.com/scenic-views/scenic/llms.txt Drops a database view. It is reversible by providing `revert_to_version`. ```APIDOC ## Migration method: `drop_view` — Drop a database view Drops the named view. Always supply `revert_to_version:` to allow rollbacks to recreate it. ```ruby class DropSearchResults < ActiveRecord::Migration[7.1] def change drop_view :search_results, revert_to_version: 2 # Drop a materialized view drop_view :daily_stats, revert_to_version: 3, materialized: true end end ``` ``` -------------------------------- ### update_view Source: https://context7.com/scenic-views/scenic/llms.txt Updates an existing view to a new version. This method drops the old view and recreates it from the new SQL definition. It is reversible by providing `revert_to_version`. ```APIDOC ## Migration method: `update_view` — Update a view to a new version Drops the existing view and recreates it from the new version's SQL file. Always provide `revert_to_version:` to make the migration reversible. For materialized views, indexes are automatically reapplied after the update. ```ruby class UpdateSearchResultsToVersion2 < ActiveRecord::Migration[7.1] def change # Standard view update – reversible via revert_to_version update_view :search_results, version: 2, revert_to_version: 1 # Materialized view update (drops and recreates, reapplies indexes) update_view :daily_stats, version: 2, revert_to_version: 1, materialized: true # Materialized view updated with side-by-side strategy (requires a transaction) # Creates new view under a temp name, refreshes data, then atomically swaps update_view :heavy_report, version: 2, revert_to_version: 1, materialized: { side_by_side: true } # Update materialized view without loading data update_view :heavy_report, version: 3, revert_to_version: 2, materialized: { no_data: true } end end ``` ``` -------------------------------- ### Refresh Materialized Views Source: https://context7.com/scenic-views/scenic/llms.txt Use `Scenic.database.refresh_materialized_view` to repopulate materialized views. Supports concurrent and cascade refresh options. ```ruby Scenic.database.refresh_materialized_view(:daily_stats) ``` ```ruby Scenic.database.refresh_materialized_view(:search_results, concurrently: true) ``` ```ruby Scenic.database.refresh_materialized_view(:summary_report, cascade: true) ``` ```ruby Scenic.database.refresh_materialized_view(:summary_report, concurrently: true, cascade: true ) ``` ```ruby class DailyStat < ApplicationRecord def self.refresh Scenic.database.refresh_materialized_view(table_name, concurrently: false, cascade: false) end end ``` ```ruby DailyStat.refresh ``` -------------------------------- ### Update View Definition with New Columns Source: https://github.com/scenic-views/scenic/blob/main/README.md If underlying table columns are missing from a view, ensure the view definition was created with `SELECT [table_name].*`. To include new columns, update the view definition using `update_view` with an incremented `version`. ```ruby add_column :posts, :title, :string update_view :posts_with_aggregate_data, version: 2, revert_to_version: 2 ``` -------------------------------- ### Check if Materialized View is Populated Source: https://context7.com/scenic-views/scenic/llms.txt Use `Scenic.database.populated?` to check if a materialized view has data. This is useful before querying or refreshing. ```ruby if Scenic.database.populated?(:heavy_report) puts "View is ready to query" else Scenic.database.refresh_materialized_view(:heavy_report) end ``` ```ruby unless HeavyReport.populated? HeavyReport.refresh end ``` -------------------------------- ### populated? Source: https://context7.com/scenic-views/scenic/llms.txt Checks if a materialized view has been populated with data. Returns `true` if populated, `false` if created with `WITH NO DATA` and not yet refreshed. ```APIDOC ## `Scenic.database.populated?` — Check if a materialized view is populated Returns `true` if the materialized view has been populated with data, `false` if it was created with `WITH NO DATA` and has not yet been refreshed. ```ruby if Scenic.database.populated?(:heavy_report) puts "View is ready to query" else Scenic.database.refresh_materialized_view(:heavy_report) end # Via the generated model method: unless HeavyReport.populated? HeavyReport.refresh end ``` ``` -------------------------------- ### Replace Database Views in Rails Migrations Source: https://context7.com/scenic-views/scenic/llms.txt Use `replace_view` with `CREATE OR REPLACE VIEW` for non-materialized views. This method retains dependent views and has restrictions on column changes. ```ruby replace_view :search_results, version: 2, revert_to_version: 1 ``` -------------------------------- ### Update Database Views in Rails Migrations Source: https://context7.com/scenic-views/scenic/llms.txt Use `update_view` to upgrade views to a new version. Always provide `revert_to_version` for reversibility. Supports materialized views with options like `side_by_side` or `no_data`. ```ruby update_view :search_results, version: 2, revert_to_version: 1 ``` ```ruby update_view :daily_stats, version: 2, revert_to_version: 1, materialized: true ``` ```ruby update_view :heavy_report, version: 2, revert_to_version: 1, materialized: { side_by_side: true } ``` ```ruby update_view :heavy_report, version: 3, revert_to_version: 2, materialized: { no_data: true } ``` -------------------------------- ### Set Primary Key for View-Backed Models Source: https://github.com/scenic-views/scenic/blob/main/README.md When querying view-backed models with `find`, `last`, or `first`, set the `primary_key` attribute on the Rails model to the corresponding column name in your database. This is necessary because views do not have inherent primary keys. ```ruby class People < ApplicationRecord self.primary_key = :my_unique_identifier_field end ``` -------------------------------- ### Replace View Migration Ruby Code Source: https://github.com/scenic-views/scenic/blob/main/README.md This Ruby migration uses the `replace_view` method to update an existing view. It specifies the view name, the new version, and the version to revert to. ```ruby class UpdateSearchResultsToVersion2 < ActiveRecord::Migration def change replace_view :search_results, version: 2, revert_to_version: 1 end end ``` -------------------------------- ### Define Search Results View SQL Source: https://github.com/scenic-views/scenic/blob/main/README.md This SQL statement defines the structure and data for the 'search_results' view. It combines results from statuses and comments using a UNION. ```sql SELECT statuses.id AS searchable_id, 'Status' AS searchable_type, comments.body AS term FROM statuses JOIN comments ON statuses.id = comments.status_id UNION SELECT statuses.id AS searchable_id, 'Status' AS searchable_type, statuses.body AS term FROM statuses ``` -------------------------------- ### Drop Database Views in Rails Migrations Source: https://context7.com/scenic-views/scenic/llms.txt Use `drop_view` to remove a database view. Provide `revert_to_version` to enable rollbacks. This method works for both standard and materialized views. ```ruby drop_view :search_results, revert_to_version: 2 ``` ```ruby drop_view :daily_stats, revert_to_version: 3, materialized: true ``` -------------------------------- ### Refresh a Materialized View Source: https://github.com/scenic-views/scenic/blob/main/README.md This convenience method aids in scheduling refreshes for materialized views. By default, it performs a non-concurrent refresh, locking the view during the process. ```ruby def self.refresh Scenic.database.refresh_materialized_view(table_name, concurrently: false, cascade: false) end ``` -------------------------------- ### Drop a Database View Source: https://github.com/scenic-views/scenic/blob/main/README.md Use `drop_view` within a Rails migration to remove a database view. You can specify the view name, the version to revert to, and whether it's a materialized view. ```ruby def change drop_view :search_results, revert_to_version: 2 drop_view :materialized_admin_reports, revert_to_version: 3, materialized: true end ``` -------------------------------- ### refresh_materialized_view Source: https://context7.com/scenic-views/scenic/llms.txt Refreshes a materialized view to update its data. Supports concurrent refresh (no read lock) and cascade refresh (refreshes dependencies first). ```APIDOC ## `Scenic.database.refresh_materialized_view` — Refresh a materialized view Called from application code (e.g., a scheduled job or Rake task) to repopulate a materialized view from its SQL definition. Supports concurrent refresh (no read lock, requires a unique index) and cascade refresh (refreshes dependent views first in topological order). ```ruby # Non-concurrent refresh — locks the view for selects during refresh Scenic.database.refresh_materialized_view(:daily_stats) # Concurrent refresh — does not lock; requires PostgreSQL 9.4+ and a unique index Scenic.database.refresh_materialized_view(:search_results, concurrently: true) # Cascade refresh — refreshes all dependencies first, then the target view Scenic.database.refresh_materialized_view(:summary_report, cascade: true) # Concurrent + cascade Scenic.database.refresh_materialized_view(:summary_report, concurrently: true, cascade: true ) # Typically wrapped in the model class itself: class DailyStat < ApplicationRecord def self.refresh Scenic.database.refresh_materialized_view(table_name, concurrently: false, cascade: false) end end # In a Rake task or background job: DailyStat.refresh ``` ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.