Home

Awesome

Gem Version Build Status Coverage Status

SchemaPlus::Views

SchemaPlus::Views adds support for creating and dropping views in ActiveRecord migrations, as well as querying views.

SchemaPlus::Views is part of the SchemaPlus family of Ruby on Rails extension gems.

Installation

<!-- SCHEMA_DEV: TEMPLATE INSTALLATION - begin --> <!-- These lines are auto-inserted from a schema_dev template -->

As usual:

gem "schema_plus_views"                # in a Gemfile
gem.add_dependency "schema_plus_views" # in a .gemspec
<!-- SCHEMA_DEV: TEMPLATE INSTALLATION - end -->

Compatibility

SchemaPlus::Views is tested on:

<!-- SCHEMA_DEV: MATRIX - begin --> <!-- These lines are auto-generated by schema_dev based on schema_dev.yml --> <!-- SCHEMA_DEV: MATRIX - end -->

Usage

Creating views

In a migration, a view can be created using literal SQL:

create_view :uncommented_posts, "SELECT * FROM posts LEFT OUTER JOIN comments ON comments.post_id = posts.id WHERE comments.id IS NULL"

or using an object that responds to :to_sql, such as a relation:

create_view :posts_commented_by_staff,  Post.joins(comment: user).where(users: {role: 'staff'}).uniq

(It's of course a questionable idea for your migration files to depend on your model definitions. But you can if you want.)

Additional options can be provided:

SchemaPlus::Views also arranges to include the create_view statements (with literal SQL) in the schema dump.

Materialized views

Materialized views persist their data when created and must be manually refreshed to see new data. Further materialized views can have indexes defined on them.

create_view :posts_commented_by_staff, <<~SQL, materialized: true
SELECT * FROM posts LEFT OUTER JOIN comments ON comments.post_id = posts.id WHERE comments.id IS NULL
SQL

add_index :posts_commented_by_staff, :category
add_index :posts_commented_by_staff, :token, unique: true

To refresh a materialized view run the refresh_view connection command.

ActiveRecord::Base.connection.refresh_view('posts_commented_by_staff')

Dropping views

In a migration:

drop_view :posts_commented_by_staff
drop_view :uncommented_posts, :if_exists => true

# materialized views
drop_view :posts_commented_by_staff, materialized: true
drop_view :uncommented_posts, :if_exists => true, materialized: true

Using views

ActiveRecord models can be based on views the same as ordinary tables. That is, for the above views you can define

class UncommentedPost < ActiveRecord::Base
end

class PostCommentedByStaff < ActiveRecord::Base
  table_name = "posts_commented_by_staff"
end

Querying views

You can look up the defined views analogously to looking up tables:

connection.tables # => array of table names [method provided by ActiveRecord]
connection.views  # => array of view names [method overridden by SchemaPlus::Views for postgres]

Notes:

  1. For PostgreSQL, connection.views suppresses views prefixed with pg_ as those are presumed to be internal. Also it suppresses the "postgis" specifically named tables
    • geography_columns
    • geometry_columns
    • raster_columns
    • raster_overviews

Querying view definitions

You can look up the definition of a view using

connection.view_definition(view_name) # => returns SQL string

This returns just the body of the definition, i.e. the part after the CREATE VIEW 'name' AS command.

You can also lookup the type of view (regular or materialized) using

connection.view_type(view_name) # => returns a Symbol, either :view or :materialized

Customization API: Middleware Stacks

All the methods defined by SchemaPlus::Views provide middleware stacks, in case you need to do any custom filtering, rewriting, triggering, or whatever. For info on how to use middleware stacks, see the READMEs of schema_monkey and schema_plus_core.

Schema::ViewDefinition stack

Wraps the connection.view_full_definition method. Env contains:

Env FieldDescriptionInitialized
:connectionThe current ActiveRecord connectioncontext
:view_nameThe view to look uparg
:query_nameOptional label for ActiveRecord loggingarg
:definitionThe view definition SQLnil
:view_typeThe view type symbol.:view`

The base implementation looks up the definition of the view named env.view_name and assigns the result to env.definition

Migration::CreateView stack

Wraps the migration.create_view method. Env contains:

Env FieldDescriptionInitialized
:connectionThe current ActiveRecord connectioncontext
:view_nameThe view namearg
:definitionThe view definition SQLarg
:optionsCreate view optionsarg

The base implementation creates the view named env.view_name using the definition in env.definition with options in env.options

Migration::DropView stack

Wraps the migration.drop_view method. Env contains:

Env FieldDescriptionInitialized
:connectionThe current ActiveRecord connectioncontext
:view_nameThe view namearg
:optionsDrop view optionsarg

The base implementation drops the view named env.view_name using the options in env.options

History

Development & Testing

Are you interested in contributing to SchemaPlus::Views? Thanks! Please follow the standard protocol: fork, feature branch, develop, push, and issue pull request.

Some things to know about to help you develop and test:

<!-- SCHEMA_DEV: TEMPLATE USES SCHEMA_DEV - begin --> <!-- These lines are auto-inserted from a schema_dev template --> <!-- SCHEMA_DEV: TEMPLATE USES SCHEMA_DEV - end --> <!-- SCHEMA_DEV: TEMPLATE USES SCHEMA_PLUS_CORE - begin --> <!-- These lines are auto-inserted from a schema_dev template --> <!-- SCHEMA_DEV: TEMPLATE USES SCHEMA_PLUS_CORE - end --> <!-- SCHEMA_DEV: TEMPLATE USES SCHEMA_MONKEY - begin --> <!-- These lines are auto-inserted from a schema_dev template --> <!-- SCHEMA_DEV: TEMPLATE USES SCHEMA_MONKEY - end -->