Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Bower components Debian packages RPM packages NuGet packages

universityofyork / uoy-faculty-sinatra   ruby

Repository URL to install this package:

  bin
  lib
  Gemfile
  README.md
  uoy-faculty-sinatra.gemspec
 
  README.md

Sinatra Helpers Gem

Installation

Add these lines to your application's Gemfile:

source 'https://gem.fury.io/universityofyork/' do
  gem 'uoy-faculty-sinatra', '~> 0.1', require: 'sinatra'
end

And then execute:

$ bundle

Or install it yourself as:

$ gem install uoy-faculty-sinatra

Usage

Functions for use in configure block

  • no_master_web_library_in_production!
    • Will raise an exception if we are trying to use the master web library in production
configure do
  no_master_web_library_in_production!
end

Helpers

  • current_url?(path)
    • Checks if the given path is the current page being show
    • Useful in the navbar (e.g. current_url? '/staff')
  • full_url(relative_url)
    • Gets the full path of a relative URL with the hostname
    • e.g. on a local server, rel('/login') => https://app.domain/app/app_name/login
  • path_with_web_root
    • Returns the full path of the current page including the web root
    • Given to BootstrapNavbar so the current page can be highlighted correctly
  • rel(relative_url)
    • Gets the full path of a relative URL
    • e.g. on a local server, rel('/login') => /app/app_name/login
  • web_library(resource)
    • Generates a URL to the given resource in the web library
    • Will use S3 bucket if not local; otherwise, the /web-library subdirectory
    • e.g. web_library('css/app.css') => /path/to/library/css/app.css
  • web_root
    • Returns the root path of the app, without a trailing slash
    • e.g. '' in AWS; /app/app_name on a local server

Auth

For local development:

configure do
  register Sinatra::BasicPasswordlessAuth
end

We can register different Auth schemes depending on environment (e.g. Cognito auth in AWS)

HTTP Status

Define rescuable HTTP statuses.

get '/path/ do
  raise http_status(403) unless user_can_view_this_page?
end

We can define custom error pages in app.rb:

error_handler HTTPStatus::AnyStatus, :error
error_handler HTTPStatus::Forbidden, :'error/403'
error_handler HTTPStatus::NotFound, :'error/404'
error(Sinatra::NotFound) { erb :'error/404' }

Validation

General Parameter Validation

param_validator :valid_user do
  param :id, Integer, required: true
end

post '/user-record/id', validate_params: :valid_user do
  # ...your logic here...
end

General validation will return a 403 forbidden error if the validation fails.

Form Validation

form_validator :sample_form do 
  param :name, String, required: true
  param :day, Date, required: true, message: 'Must provide a Date'
  one_of :a, :b
end

post '/sample-form', validate_form: :sample_form do
  # ...your logic here...
end

If the validator fails, it will redirect back to the form and flash the form params to the session. To make use of these params, you should use the form_value helper. There is also a form_error? helper for checking if a specific field had an error, and invalid_feedback to retrieve the error for the given field.

<input type="text" class="form-control <%= 'is-invalid' if form_error? :name %>" 
       name="name" id="name" required 
       value="<%= form_value :name %>">
<div class="invalid-feedback">
  <%= invalid_feedback :name, 'Please provide an event name.' %>
</div>

If your form should already have values populated, you can use the form_values helper in your route. This sets the default values for fields, which will be overridden by flashed values if they exist.

get '/sample-form' do
  form_values({ name: 'Foo' })
  erb :sample_form
end

Common options

param, one_of and any_of are valid methods on the validator object; see sinatra/param for details of these methods.

If you have code you wish to run that depends on a parameter value, you can pass a block. This will run immediately after the parameter was validated - unless the parameter was invalid, in which case it will not be run.

param_validator :block_example do
  param :user_id, Integer, required: true do
    @user = get_user(params[:user_id])
  end
end

If you wish to run some code in the context of the route, use block. This will always be run, so be aware if using previously validated parameters, there is no guarantee they will be valid.

param_validator :block_test do
  block do
    #...
  end
end

Multiple validators can be passed as an array:

post '/sample-form', validate_form: %i[validator1 validator2] do
  # ...your logic here...
end

Validators can take parameters, which can be passed by wrapping the validator identifier with validator:

param_validator :sample do |parameter|
  # ...
end

post '/sample', validate_params: validator(:sample, parameter) do
  # ...your logic here...
end

Flash Messages

Pass messages to the next page through the session. This extends the standard sinatra-flash implementation and uses a single key for all flash messages, so we can define multiple messages with the same type.

Pass a message and a message type (a bootstrap contextual class, e.g. :success or :danger; defaults to :info) in your route:

flash_message 'The default type is "info".'
flash_message 'Added something successfully.', type: :success
flash_message 'We want to warn you about something.', type: :warning

And add the template to your view, where appropriate:

<%== erb :flash_messages %>

You can also pass an array of messages for a single type, which will be output in a single alert, one per line:

flash_message ['Added A.', 'Added B.']

Development

Versioning

Your Gem's version is picked up automatically from lib/sinatra.rb. When any changes are pushed to master, after the normal CI tasks the pipeline will push to gemfury automatically. The usual workflow is:

  • For minor changes, update VERSION and make the change in a single commit

  • For anything else, create a branch and set VERSION to the version you're aiming to release for. Make the changes; when the branch is merged, the gem will be uploaded.

Note that gemfury will never overwrite an existing gem version, even if the old one is yanked!

Running tests

Tests can be run via rake: bundle exec rake spec - this doesn't run performance tests; they can be run separately via bundle exec rake perf.

You can also run rspec normally e.g. bundle exec rspec -fd.

Identifying Performance Tests

If you have performance tests that take a while, tag the context / describe block like this:

context 'when foo is bar baz', :perf do
  ...
end

Contributing

Bug reports and pull requests are welcome at https://github.com/university-of-york/faculty-dev-sinatra-gem