Skip to content

Latest commit

 

History

History
1321 lines (957 loc) · 54.1 KB

README.rdoc

File metadata and controls

1321 lines (957 loc) · 54.1 KB

Padrino (padrino-core)

Padrino is the godfather of Sinatra.

Preface

Padrino is a ruby framework built upon the Sinatra Microframework.

Sinatra is a DSL for quickly creating web applications in Ruby with minimal effort. This gem represents an attempt to make it as fun and easy as possible to code increasingly advanced web applications in Sinatra.

Introduction

Many people love Sinatra’s simplicity and lightweight but often quickly come to miss a great deal of functionality provided by other web frameworks such as Rails when building non-trivial applications.

The obvious question in these cases might be “Why not just use rails then?”. This can often be a viable option but still Rails is quite a large framework with a ‘take it or leave it’ attitude.

Personally, we have come to love the philosophy of Sinatra which acts as a thin layer on top of rack often allowing middleware to do most of the work and pulling in additional complexity only when required.

Our goal with this framework is to match the essence of Sinatra and at the same time create a standard library of tools, helpers and components that will make Sinatra suitable for more complex applications.

Here is a small list of what Padrino provides:

Generators

for creating new padrino applications i.e.: padrino-gen app or padrino start on command line

MultiApp

unlike other ruby frameworks Padrino is principally designed for mounting multiple apps at the same time.

Routing

Full url named route, named params, respond_to suppor

Tag Helpers

helpers such as: tag, content_tag, input_tag, …

Asset Helpers

helpers such as: link_to, image_tag, javascript_include_tag, …

Form Helpers

with builder support such as: form_tag, form_for, field_set_tag, text_field, …

Text Helpers

useful formatting extensions like: relative_time_ago, js_escape_html, sanitize_html

Mailer

fast, tiny, delivery support for send templating emails (like ActionMailer do)

Admin

an ajax admin that displays your records in sortable grids, tree, windows … as a desktop app can do.

Logging

Padrino provide a logger that can interact with your orm or any other library

Reloading

With padrino is not necessary like other framework start and restart your server for see changes.

I18n

Padrino has a full support of I18n and can autoset locale.

Keep in mind, the user will be able to pull in these components seperately and leave out those that are not required or use them altogether for a comprehensive upgrade to Sinatra (a full-stack Padrino application).

Note that all work has been created to be compatible with haml, erb, and erubis and that this gem is intended to be template-agnostic in providing helpers wherever possible.

Please help me brainstorm and fork the project if you have any ideas to contribute.

Installation

To install the padrino framework, simply grab the latest version from gemcutter:

$ sudo gem install padrino

This will install the necessary padrino gems to get you started. Now you are ready to use this gem to enhance your sinatra projects or to create new Padrino applications.

Usage

Padrino is a framework which builds on the existing functionality and Sinatra and provides a variety of additional tools and helpers to extend the foundation. This README and Padrino documentation in general will focus on the enhancements to the core Sinatra functionality. To use Padrino, one should be familiar with the basic usage of Sinatra itself. Resources for Sinatra are listed below:

Below is a guide to how this gem enhances the Sinatra framework as part of a ‘full-stack’ padrino application. For information on how to use a specific gem in isolation within an existing Sinatra project, checkout the README for that individual gem or gems.

Enhanced Base Application (padrino-core)

Sinatra has support for classes which can be extended to create an application: Sinatra::Base and Sinatra::Application These classes can be extended in order to create a Sinatra web application. These classes provide support for all the basic functionality afforded by Sinatra.

Padrino has support for an enhanced base application class Padrino::Application. Padrino::Application expands the capabilities of Sinatra::Application and automatically provides the resulting application access to all of the padrino framework’s functionalities.

Similar in spirit to Sinatra itself, Padrino application layout is extremely flexible and can be as small as a single file. However, Padrino provides many extensions which improve upon the ability to construct more complex applications.

Simple Application Definition

Let us first take a look at the simplest possible Padrino application:

# app.rb
PADRINO_ROOT = File.dirname(__FILE__) unless defined? PADRINO_ROOT
require 'padrino'
Padrino.load!

class SimpleApp < Padrino::Application
  get '/' do
    'Hello world'
  end

  # and for read better we can divide with controllers
  controller '/admin' do
    get '/foo' do
      'Im /admin/foo'
    end
  end
end

Controllers

Suppose we wanted to add additional routes to our Padrino application, and we want to organize the routes within a more structured layout. Simply add a controllers or app/controllers folder and create a file as such:

# Simple Example
SimpleApp.controllers do
  get "/test" do
    "Text to return"
  end
end

Advanced Routing Support

Padrino provides support for advanced routing functionality not available within Sinatra. This routing supports named route aliases and easy access to url paths. The benefits of this is that instead of having to hard-code route urls into every area of your application, now we can just define the urls in a single spot and then attach an alias which can be used to refer to the url throughout the application.

Padrino Routing

Urls mapped here can then be defined within a controller:

# app/controllers/example.rb
SimpleApp.controllers do
  get :index do
    ...
  end

  get :account do
    # access params[:name] and params[:index]
  end
end

and finally referenced anywhere in the application:

# app/views/example.haml
= link_to "Index", url_for(:index)
= link_to "Account", url_for(:account, :id => 1, :name => 'first')

Inline Route Alias Definitions

The routing plugin also supports inline route definitions in which the url and the named alias are defined together within the controller:

# app/controllers/example.rb
SimpleApp.controllers do
  get :index, :map => '/index' do
    ...
  end

  get :account, :map => '/the/accounts/:name/and/:id' do
    # access params[:name] and params[:index]
  end
end

Routes defined inline this way can be accessed and treated the same way as traditional named aliases.

Namespaced Route Aliases

There is also support for namespaced routes which are organized into a larger grouping:

# app/controllers/example.rb
SimpleApp.controllers :admin do
  get :show do
    "Im /admin/show"
  end

  get :index, :map => "/admin/:id" do
    "Im /admin/#{params[:id]}"
  end
end

You can then reference the urls using the same url_for method:

<%= link_to 'admin show page', url_for(:admin_show, :id => 25) %>
<%= link_to 'admin index page', url_for(:admin_index, :id => 25) %>

If you don’t want named routes you can

# app/controllers/example.rb
SimpleApp.controllers "/admin" do
  get "/show" do
    "Im /admin/show"
  end

  get "other/:id" do
    "Im /admin/#{params[:id]}"
  end
end

Named Params

With Padrino you can use named params!! See these examples

# app/controllers/example.rb
SimpleApp.controllers :admin do
  get :show, :with => :id do
    "Im /admin/show/#{params[:id]}"
  end

  get :other, with => [:id, :name]  do
    "Im /admin/#{params[:id]}/#{params[:name]}"
  end
end

You can then reference the urls using the same url_for method:

<%= link_to 'admin show page', url_for(:admin_show, :id => 25) %>
<%= link_to 'admin other page', url_for(:admin_index, :id => 25, :name => :foo) %>

Respond To

With Padrino you can simply respond to a given format see example:

# app/controllers/example.rb
SimpleApp.controllers :admin do
  get :show, :with => :id, :respond_to => :js do
    "Im /admin/show/#{params[:id]}.#{params[:format]}"
  end

  get :other, with => [:id, :name], respond_to => [:html, :json] do
    case content_type
      when :js    then ... end
      when :json  then ... end
    end
  end
end

<%= link_to 'admin show page', url_for(:admin_show, :id => 25, :format => :js) %>
<%= link_to 'admin other page', url_for(:admin_index, :id => 25, :name => :foo) %>
<%= link_to 'admin other json page', url_for(:admin_index, :id => 25, :name => :foo, :format => :json) %>

Rendering

Unlike Sinatra Padrino support template auto lookup so:

# look for 'account/index.{erb,haml,...}
render 'account/index'

Layout

With Padrino you can (like rails do) use for your custom layout, disable it

class SimpleApp < Padrino::Application

  # Disable layouts
  disable layout

  # Use the layout located in views/layouts/custom.haml
  layout :custom

Gemfile Dependency Resolution

While this is a fully operational Padrino application in itself, let us take a look at Padrino’s expanded capabilites. First, we can create Gemfile within the application root. This will contain a list of all the dependencies for our application.

# /Gemfile
clear_sources
source 'http://gemcutter.org'
gem 'sinatra',     :require => 'sinatra/base'
gem 'rack-flash'

This manifest file uses the standard bundler gem syntax of which details can be found in the Bundler README This gem allows us to place all our dependencies into a single file. Padrino will then automatically require all necessary files (if they exist on the system).

If the dependencies are not on the system, you can automatically vendor all necessary gems using the gem bundle command within the application root. Note that this is all possible without any further effort than adding the Gemfile (or having this generated automatically with generators explained later).

Auto Load Paths

Padrino also intelligently supports requiring useful files within your application automatically and provides functionality for easily splitting up your application into separate files. Padrino automatically requires config/database.rb as a convention for establishing database connection. Also, any files within the lib folder will be required automatically by Padrino.

This is powered by the fact that Padrino will automatically load (and reload) any directory patterns within the ‘load path’. Additional directory patterns can be added to the load path as needed by simply appending to the load_paths within your application:

# app.rb
class SimpleApp < Padrino::Application
  load_paths << ["app/special/*.rb", "some_file.rb"]
end

This will instruct Padrino to autoload these files (and reload them when changes are detected). By default, the load path contains certain paths known to contain important files such as controllers, mailers, models, urls, and helpers.

Initializers are automatically required and ‘registered’ during the application startup process. Note that the name of the module must be the name of the file appended with ‘Initializer’ (i.e sample.rb => SampleInitializer)

Application Logging

Padrino also supports robust logging capabilities. By default, logging information will go to the STDOUT in development (for use in a console) and in an environment-specific log file log/development.log in test and production environments.

You can modify the logging behavior or disable logging altogether:

# app.rb
class SimpleApp < Padrino::Application
  disable :logging     # Turns off logging
  enable  :log_to_file # Forces logging to be written to a file
end

To use the logger within a Padrino application, simply refer to the logger method accessible within your app and any controller or views:

# controllers/example.rb
SimpleApp.controllers do
  get("/test") { logger.info "This is a test" }
end

The logger automatically supports severity through the use of logger.info, logger.warn, logger.error, et al. For more information about the logger, check out the Logger RDOC

Mounting Applications

Padrino applications are all automatically mountable into other Padrino projects. This means that a given Padrino project directory can easily mount multiple applications. This allows for better organization of complex applications, re-usable applications that can be applied (i.e admin, auth, blog) and even more flexibility.

You can think of mountable applications as a ‘full-featured’ merb slice or rails engine. Instead of a separate construct, any application can simply be packaged and mounted into another project.

Padrino stores application mounting information by default within config/apps.rb. This file is intended to keep all information regarding what applications are mounted to which uri’s. An apps.rb file has the following structure:

Padrino.mount("blog").to("/blog")
Padrino.mount("website").to("/website")

This would mount two applications onto the Padrino project, one served from the ‘/blog’ uri namespace and the other served from the ‘/website’ uri namespace. Often a Padrino project directory requires a single ‘core’ application which is served from the uri root. This can be easily configured using:

Padrino.mount_core("app_name") # mounts app with class AppName, in file <tt>app/app.rb</tt>
Padrino.mount_core("app_name", :app_file => Padrino.root('app.rb')) # now with file in <tt>app.rb</tt>

This will mount a ‘core’ application with class AppName from the file ‘app.rb’ to the uri root which will act as a primary application.

Development Reloader

Padrino applications also have the enabled ability to automatically reload all changing application files without the need to restart the server. Through the use of a customized Rack middleware, all files on the ‘load path’ are monitored and reloaded whenever changes are applied.

This makes rapid development much easier and provides a better alternative to ‘shotgun’ or ‘rerun’ which require the application server to be restarted which makes requests take much longer to complete.

An application can explicitly enable / disable reloading through the use of options:

# app.rb
class SimpleApp < Padrino::Application
  disable :reload # reload is disabled in all environments
  enable  :reload # enabled in all environments
end

By default, reloading is enabled in development and disabled in the test and production environments.

If you want to build a standalone app you need to take some precautions see example:

# simple_demo.rb
PADRINO_ROOT = File.dirname(__FILE__) unless defined? PADRINO_ROOT
require 'padrino-core'

class SimpleDemo < Padrino::Application
  set :reload, true

  get "/" do
    "This is a simple Demo!!!"
  end
end

Padrino.mount_core("SimpleDemo")

Padrino.run! unless Padrino.loaded? # If you enable reloader prevent to re-run the app

Padrino.load!

Now you can run simple_demo.rb with:

$ ruby simple_demo.rb

Browse localhost:3000 edit your file and refresh your page for see changes!

Terminal Commands

Padrino also comes equipped with multiple useful terminal commands which can be activated to perform common tasks such as starting / stopping the application, executing the unit tests or activating an irb session.

The following commands are available:

# starts the app server (non-daemonized)
$ padrino start 
# starts the app server (daemonized) with given port, environment and adapter
$ padrino start -d -p 3000 -e development -a thin 

# Stops a daemonized app server
$ padrino stop

# Bootup the Padrino console (irb)
$ padrino console

# Run/List tasks
$ padrino rake

The last command “padrino rake” look for rake files in:

lib/tasks/**/*.rake
tasks/**/*.rake
test/test.rake
spec/spec.rake

In this way you can customize project tasks.

Using these commands can simplify common tasks making development that much smoother.

Special Folders

Padrino load these paths:

project/lib
project/models
project/shared/lib
project/shared/models
project/each_app/models

This mean that you are free to store for example models where you prefer, if you have two or more apps with same models you can use project/shared/models or root/models.

If you have only one app you still use project/app/models (this is the default padrino-gen choice)

Remember that if you need to load other paths you can use:

Padrino.set_load_paths("path/one")

and if you need to load dependencies use:

Padrino.require_dependencies("path/one/**/*.rb")

Agnostic Application Generators (padrino-gen)

Overview

Padrino comes preloaded with flexible code generators powered in part by the excellent Thor gem (incidentally also used in the Rails 3 generators). These generators are intended to allow for easy code generation both in creating new applications and building on existing ones. The generators have been built to be as library agnostic as possible, supporting a myriad of test frameworks, js libraries, mocking libraries, etc.

See the wiki article for additional information: <…WIKI…>

Application Generator

Padrino provides generator support for quickly creating new Padrino applications. This provides many benefits such as constructing the recommended Padrino application structure, auto-generating a Gemfile listing all starting dependencies and guidelines provided within the generated files to help orient a new user to using Padrino.

One important feature of the generators is that they were built from the ground up to support a wide variety of tools, libraries and gems for use within your padrino application.

This means that Padrino generators do not lock you into using any particular database, ORM, testing framework, templating engine or javascript library. In fact, when generating an application you can actually tell Padrino which components you would like to use!

The usage for the project generator is quite simple:

$ padrino-gen project <the_app_name> </path/to/create/app> --<component-name> <value>

The simplest possible command to generate a base application would be:

$ padrino-gen project demo_project

This would construct a Padrino application DemoApp (which extends from Padrino::Application) inside the folder ‘demo_project’ at our current path. Inside the application there would be configuration and setup performed for the default components.

You can also define specific components to be used:

$ padrino-gen project demo_project --test rspec --renderer haml --mock rr --script jquery --orm datamapper

There is also support for aliases for each component within the command:

$ padrino-gen project demo_project -t rspec -r haml -m rr -s jquery -d datamapper

You can also instruct the generator to skip a certain component to avoid using one at all (or to use your own):

$ padrino-gen project demo_project --test none --renderer none

The available components and their default options are listed below:

test

rspec (default), bacon, shoulda, cucumber, testspec, riot

renderer

haml (default), erb

mock

none (default), mocha, rr

script

none (default), jquery, prototype, mootools, rightjs

orm

none (default), mongomapper, mongoid, activerecord, sequel, couchrest

The generator uses the bundler gem to resolve any application dependencies when the application is newly created. The necessary bundler command can be executed automatically through the generator with

$ padrino-gen project demo_project --run_bundler # alias -b

or this can be done manually through executing command gem bundle in the terminal at the root of the generated application. If not executed manually, the bundling will be performed automatically the first time the application attempts to boot. Note that this command only has to be performed when the application is first generated or when the Gemfile is modified.

The generator framework within padrino is extensible and additional components and tools can be added easily. This would be achieved through forking our project and reading through the code in lib/generators/App.rb and the setup instructions inside the relevant files within lib/generators/components/. We are happy to accept pull requests for additional component types not originally included (although helping us maintain them would also be appreciated).

Sub App Generator

Unlike other ruby frameworks Padrino is principally designed for mounting multiple apps at the same time.

First you need to create a project

$ padrino-gen project demo_project
$ cd demo_project

Now you are in demo_project and you can create your apps:

$ padrino-gen app one
$ padrino-gen app two

By default these apps are mounted under:

* /one
* /two

but you can edit config/apps.rb and change it.

Model Generator

Padrino provides generator support for quickly creating new models within your Padrino application. Note that the models (and migrations) generated are specifically tailored towards the ORM component and testing framework chosen during application generation.

Very important to note that model generators are intended primarily to work within applications created through the Padrino application generator and that follow Padrino conventions. Using model generators within an existing application not generated by Padrino will likely not work as expected.

Using the model generator is as simple as:

$ padrino-gen model User

You can also specify desired fields to be contained within your User model:

$ padrino-gen model User name:string age:integer email:string

The model generator will create multiple files within your application and based on your ORM component. Usually the model file will generate files similar to the following:

* model definition file [app/models/user.rb]
* migration declaration [db/migrate/xxx_create_users.rb]
* model unit test file  [test/models/user_test.rb]

You can define as many models as you would like in a Padrino application using this generator.

You can destroy models that you created via the destroy option and setting it to true. default is false.

$ padrino-gen model User -d

This remove all created model files.

Migration Generator

Padrino provides generator for quickly generating new migrations to change or manipulate the database schema. These migrations generated will be tailored towards the ORM chosen when generating the application.

Very important to note that migration generators are intended primarily to work within applications created through the Padrino application generator and that follow Padrino conventions. Using migration generators within an existing application not generated by Padrino will likely not work as expected.

Using the migration generator is as simple as:

$ padrino-gen migration AddFieldsToUsers
$ padrino-gen migration RemoveFieldsFromUsers

You can also specify desired columns to be added to the migration file:

$ padrino-gen migration AddFieldsToUsers last_login:datetime crypted_password:string
$ padrino-gen migration RemoveFieldsFromUsers password:string ip_address:string

The migration generator will then construct the migration file according to your ORM component chosen within db/migrate/xxx_add_fields_to_users.rb including the columns specified in the command.

You can destroy migrations that you created via the destroy option and setting it to true. default is false.

$ padrino-gen migration AddFieldsToUsers -d

This removes the migration file.

Controller Generator

Padrino provides generator support for quickly creating new controllers within your Padrino application. Note that the controller tests are generated specifically tailored towards the testing framework chosen during application generation.

Very important to note that controller generators are intended primarily to work within applications created through the Padrino application generator and that follow Padrino conventions.

Using the controller generator is as simple as:

$ padrino-gen controller Admin

If you want create a controller for a specified sub app you can:

$ padrino-gen controller Admin -a my_sub_app

You can also specify desired actions to be added to your controller:

$ padrino-gen controller Admin get:index get:new post:create

The controller generator will then construct the controller file within app/controllers/admin.rb and also a controller test file at test/controllers/admin_controller_test.rb according to the test framework chosen during app generation. A default route will also be generated mapping to name of the controller and the route name. For example:

$ padrino-gen controller User get:index

will create a url route for :index mapping to "/user/index"

You can destroy controllers that you created via the destroy option and setting it to true. default is false.

$ padrino-gen controller User -d

This removes all created controller files.

Mailer Generator

Padrino provides generator support for quickly creating new mailers within your Padrino application. Very important to note that mailer generators are intended primarily to work within applications created through the Padrino application generator and that follow Padrino conventions.

Using the mailer generator is as simple as:

$ padrino-gen mailer UserNotifier

If you want create a mailer for a specified sub app you can:

$ padrino-gen mailer UserNotifier -a my_sub_app

You can also specify desired delivery actions to be added to the mailer:

$ padrino-gen mailer UserNotifier confirm_account welcome inactive_account

The mailer generator will then construct the mailer file within app/mailers/user_notifier.rb

You can destroy mailer that you created via the destroy option and setting it to true. default is false.

$ padrino-gen mailer UserNotifer -d

This remove all created mailer files.

Application Extensions and Helpers (padrino-helpers)

Overview

This component provides a great deal of view helpers related to html markup generation. There are helpers for generating tags, forms, links, images, and more. Most of the basic methods should be very familiar to anyone who has used rails view helpers.

Output Helpers

Output helpers are a collection of important methods for managing, capturing and displaying output in various ways and is used frequently to support higher-level helper functions. There are three output helpers worth mentioning: content_for, capture_html, and concat_content

The content_for functionality supports capturing content and then rendering this into a different place such as within a layout. One such popular example is including assets onto the layout from a template:

# app/views/site/index.erb
...
<% content_for :assets do %>
  <%= stylesheet_link_tag 'index', 'custom' %>
<% end %>
...

Added to a template, this will capture the includes from the block and allow them to be yielded into the layout:

# app/views/layout.erb
...
<head>
  <title>Example</title>
  <%= stylesheet_link_tag 'style' %>
  <%= yield_content :assets %>
</head>
...

This will automatically insert the contents of the block (in this case a stylesheet include) into the location the content is yielded within the layout.

The capture_html and the concat_content methods allow content to be manipulated and stored for use in building additional helpers accepting blocks or displaying information in a template. One example is the use of these in constructing a simplified ‘form_tag’ helper which accepts a block.

# form_tag '/register' do ... end
def form_tag(url, options={}, &block)
  # ... truncated ...
  inner_form_html = capture_html(&block)
  concat_content '<form>' + inner_form_html + '</form>'
end

This will capture the template body passed into the form_tag block and then append the content to the template through the use of concat_content. Note have been built to work for both haml and erb templates using the same syntax.

The list of defined helpers in the ‘output helpers’ category:

  • content_for(key, &block)

    • Capture a block of content to be rendered at a later time.

    • content_for(:head) { ...content... }

    • Also supports arguments passed to the content block

    • content_for(:head) { |param1, param2| ...content... }

  • yield_content(key, *args)

    • Render the captured content blocks for a given key.

    • yield_content :head

    • Also supports arguments yielded to the content block

    • yield_content :head, param1, param2

  • capture_html(*args, &block)

    • Captures the html from a block of template code for erb or haml

    • capture_html(&block) => “…html…”

  • concat_content(text="")

    • Outputs the given text to the templates buffer directly in erb or haml

    • concat_content("This will be output to the template buffer in erb or haml")

Tag Helpers

Tag helpers are the basic building blocks used to construct html ‘tags’ within a view template. There are three major functions for this category: tag, content_tag and input_tag.

The tag and content_tag are for building arbitrary html tags with a name and specified options. If the tag contains ‘content’ within then content_tag is used. For example:

tag(:br, :style => ‘clear:both’) => <br style="clear:both" />
content_tag(:p, "demo", :class => ‘light’) => <p class="light">demo</p>

The input_tag is used to build tags that are related to accepting input from the user:

input_tag :text, :class => "demo" => <input type='text' class='demo' />
input_tag :password, :value => "secret", :class => "demo"

Note that all of these accept html options and result in returning a string containing html tags.

The list of defined helpers in the ‘tag helpers’ category:

  • tag(name, options={})

    • Creates an html tag with the given name and options

    • tag(:br, :style => 'clear:both') => <br style=“clear:both” />

    • tag(:p, :content => "demo", :class => 'large') => <p class=“large”>demo</p>

  • content_tag(name, content, options={})

    • Creates an html tag with given name, content and options

    • content_tag(:p, "demo", :class => 'light') => <p class=“light”>demo</p>

    • content_tag(:p, :class => 'dark') { ...content... } => <p class=“dark”>…content…</p>

  • input_tag(type, options = {})

    • Creates an html input field with given type and options

    • input_tag :text, :class => "demo"

    • input_tag :password, :value => "secret", :class => "demo"

Asset Helpers

Asset helpers are intended to help insert useful html onto a view template such as ‘flash’ notices, hyperlinks, mail_to links, images, stylesheets and javascript. An example of their uses would be on a simple view template:

# app/views/example.haml
...
%head
  = stylesheet_link_tag 'layout'
  = javascript_include_tag 'application'
%body
  ...
  = flash_tag :notice
  %p= link_to 'Blog', '/blog', :class => 'example'
  %p Mail me at #{mail_to 'fake@faker.com', "Fake Email Link", :cc => "test@demo.com"}
  %p= image_tag 'padrino.png', :width => '35', :class => 'logo'

The list of defined helpers in the ‘asset helpers’ category:

  • flash_tag(kind, options={})

    • Creates a div to display the flash of given type if it exists

    • flash_tag(:notice, :class => 'flash', :id => 'flash-notice')

  • link_to(*args, &block)

    • Creates a link element with given name, url and options

    • link_to 'click me', '/dashboard', :class => 'linky'

    • link_to 'click me', '/dashboard', :class => 'linky', :if => @foo.present?

    • link_to 'click me', '/dashboard', :class => 'linky', :unless => @foo.blank?

    • link_to 'click me', '/dashboard', :class => 'linky', :unless => :current

    • link_to('/dashboard', :class => 'blocky') { ...content... }

  • mail_to(email, caption=nil, mail_options={})

    • Creates a mailto link tag to the specified email_address

    • mail_to "me@demo.com"

    • mail_to "me@demo.com", "My Email", :subject => "Feedback", :cc => 'test@demo.com'

  • image_tag(url, options={})

    • Creates an image element with given url and options

    • image_tag('icons/avatar.png')

  • stylesheet_link_tag(*sources)

    • Returns a stylesheet link tag for the sources specified as arguments

    • stylesheet_link_tag 'style', 'application', 'layout'

  • javascript_include_tag(*sources)

    • Returns an html script tag for each of the sources provided.

    • javascript_include_tag 'application', 'special'

Form Helpers

Form helpers are the ‘standard’ form tag helpers you would come to expect when building forms. A simple example of constructing a non-object form would be:

- form_tag '/destroy', :class => 'destroy-form', :method => 'delete' do
  = flash_tag(:notice)
  - field_set_tag do
    %p
      = label_tag :username, :class => 'first'
      = text_field_tag :username, :value => params[:username]
    %p
      = label_tag :password, :class => 'first'
      = password_field_tag :password, :value => params[:password]
    %p
      = label_tag :strategy
      = select_tag :strategy, :options => ['delete', 'destroy'], :selected => 'delete'
    %p
      = check_box_tag :confirm_delete
  - field_set_tag(:class => 'buttons') do
    = submit_tag "Remove"

The list of defined helpers in the ‘form helpers’ category:

  • form_tag(url, options={}, &block)

    • Constructs a form without object based on options

    • Supports form methods ‘put’ and ‘delete’ through hidden field

    • form_tag('/register', :class => 'example') { ... }

  • field_set_tag(*args, &block)

    • Constructs a field_set to group fields with given options

    • field_set_tag(:class => 'office-set') { }

    • field_set_tag("Office", :class => 'office-set') { }

  • error_messages_for(:record, options={})

    • Constructs list html for the errors for a given object

    • error_messages_for :user

  • label_tag(name, options={}, &block)

    • Constructs a label tag from the given options

    • label_tag :username, :class => 'long-label'

    • label_tag(:username, :class => 'blocked-label') { ... }

  • hidden_field_tag(name, options={})

    • Constructs a hidden field input from the given options

    • hidden_field_tag :session_key, :value => 'secret'

  • text_field_tag(name, options={})

    • Constructs a text field input from the given options

    • text_field_tag :username, :class => 'long'

  • text_area_tag(name, options={})

    • Constructs a text area input from the given options

    • text_area_tag :username, :class => 'long'

  • password_field_tag(name, options={})

    • Constructs a password field input from the given options

    • password_field_tag :password, :class => 'long'

  • check_box_tag(name, options={})

    • Constructs a checkbox input from the given options

    • check_box_tag :remember_me, :checked => true

  • radio_button_tag(name, options={})

    • Constructs a radio button input from the given options

    • radio_button_tag :gender, :value => 'male'

  • select_tag(name, settings={})

    • Constructs a select tag with options from the given settings

    • select_tag(:favorite_color, :options => ['1', '2', '3'], :selected => '1')

    • select_tag(:more_color, :options => [['label', '1'], ['label2', '2']])

    • select_tag(:multiple_color, :options => [...], :multiple => true)

  • file_field_tag(name, options={})

    • Constructs a file field input from the given options

    • file_field_tag :photo, :class => 'long'

  • submit_tag(caption, options={})

    • Constructs a submit button from the given options

    • submit_tag "Create", :class => 'success'

  • button_tag(caption, options={})

    • Constructs an input (type => ‘button’) from the given options

    • button_tag "Cancel", :class => 'clear'

  • image_submit_tag(source, options={})

    • Constructs an image submit button from the given options

    • image_submit_tag "submit.png", :class => 'success'

FormBuilders

Form builders are full-featured objects allowing the construction of complex object-based forms using a simple, intuitive syntax.

A form_for using these basic fields might look like:

- form_for @user, '/register', :id => 'register' do |f|
  = f.error_messages
  %p
    = f.label :username, :caption => "Nickname"
    = f.text_field :username
  %p
    = f.label :email
    = f.text_field :email
  %p
    = f.label :password
    = f.password_field :password
  %p
    = f.label :is_admin, :caption => "Admin User?"
    = f.check_box :is_admin
  %p
    = f.label :color, :caption => "Favorite Color?"
    = f.select :color, :options => ['red', 'black']
  %p
    - fields_for @user.location do |location|
      = location.text_field :street
      = location.text_field :city
  %p
    = f.submit "Create", :class => 'button'

The list of defined helpers in the ‘form builders’ category:

  • form_for(object, url, settings={}, &block)

    • Constructs a form using given or default form_builder

    • Supports form methods ‘put’ and ‘delete’ through hidden field

    • Defaults to StandardFormBuilder but you can easily create your own!

    • form_for(@user, '/register', :id => 'register') { |f| ...field-elements... }

    • form_for(:user, '/register', :id => 'register') { |f| ...field-elements... }

  • fields_for(object, settings={}, &block)

    • Constructs fields for a given object for use in an existing form

    • Defaults to StandardFormBuilder but you can easily create your own!

    • fields_for @user.assignment do |assignment| ... end

    • fields_for :assignment do |assigment| ... end

The following are fields provided by AbstractFormBuilder that can be used within a form_for or fields_for:

  • error_messages(options={})

    • Displays list html for the errors on form object

    • f.errors_messages

  • label(field, options={})

    • f.label :name, :class => 'long'

  • text_field(field, options={})

    • f.text_field :username, :class => 'long'

  • check_box(field, options={})

    • Uses hidden field to provide a ‘unchecked’ value for field

    • f.check_box :remember_me, :uncheck_value => 'false'

  • radio_button(field, options={})

    • f.radio_button :gender, :value => 'male'

  • hidden_field(field, options={})

    • f.hidden_field :session_id, :class => 'hidden'

  • text_area(field, options={})

    • f.text_area :summary, :class => 'long'

  • password_field(field, options={})

    • f.password_field :secret, :class => 'long'

  • file_field(field, options={})

    • f.file_field :photo, :class => 'long'

  • select(field, options={})

    • f.select(:state, :options => ['California', 'Texas', 'Wyoming'])

    • f.select(:state, :collection => @states, :fields => [:name, :id])

    • f.select(:state, :options => [...], :include_blank => true)

  • submit(caption, options={})

    • f.submit "Update", :class => 'long'

  • image_submit(source, options={})

    • f.image_submit "submit.png", :class => 'long'

There is also an additional StandardFormBuilder which builds on the abstract fields that can be used within a form_for.

A form_for using these standard fields might be:

- form_for @user, '/register', :id => 'register' do |f|
  = f.error_messages
  = f.text_field_block :name, :caption => "Full name"
  = f.text_field_block :email
  = f.check_box_block  :remember_me
  = f.select_block     :fav_color, :options => ['red', 'blue']
  = f.password_field_block :password
  = f.submit_block "Create", :class => 'button'

and would generate this html (with each input contained in a paragraph and containing a label):

<form id="register" action="/register" method="post">
  <p><label for="user_name">Full name: </label><input type="text" id="user_name" name="user[name]"></p>
  ...omitted...
  <p><input type="submit" value="Create" class="button"></p>
</form>

The following are fields provided by StandardFormBuilder that can be used within a form_for or fields_for:

  • text_field_block(field, options={}, label_options={})

    • text_field_block(:nickname, :class => 'big', :caption => "Username")

  • text_area_block(field, options={}, label_options={})

    • text_area_block(:about, :class => 'big')

  • password_field_block(field, options={}, label_options={})

    • password_field_block(:code, :class => 'big')

  • file_field_block(field, options={}, label_options={})

    • file_field_block(:photo, :class => 'big')

  • check_box_block(field, options={}, label_options={})

    • check_box_block(:remember_me, :class => 'big')

  • select_block(field, options={}, label_options={})

    • select_block(:country, :option => ['USA', 'Canada'])

  • submit_block(caption, options={})

    • submit_block(:username, :class => 'big')

  • image_submit_block(source, options={})

    • image_submit_block('submit.png', :class => 'big')

You can also easily build your own FormBuilder which allows for customized fields and behavior:

class MyCustomFormBuilder < AbstractFormBuilder
  # Here we have access to a number of useful variables
  #
  #   * template  (use this to invoke any helpers)(ex. template.hidden_field_tag(...))
  #   * object    (the record for this form) (ex. object.valid?)
  #   * object_name (object's underscored type) (ex. object_name => 'admin_user')
  #
  # We also have access to self.field_types => [:text_field, :text_area, ...]
  # In addition, we have access to all the existing field tag helpers (text_field, hidden_field, file_field, ...)
end

Once a custom builder is defined, any call to form_for can use the new builder:

- form_for @user, '/register', :builder => 'MyCustomFormBuilder', :id => 'register' do |f|
  ...fields here...

The form builder can even be made into the default builder when form_for is invoked:

# anywhere in the Padrino or Sinatra application
set :default_builder, 'MyCustomFormBuilder'

And there you have it, a fairly complete form builder solution for Padrino (and Sinatra). I hope to create or merge in an even better ‘default’ form_builder in the near future.

Format Helpers

Format helpers are several useful utilities for manipulating the format of text to achieve a goal. The four format helpers are escape_html, relative_time_ago, time_in_words, and js_escape_html.

The escape_html and js_escape_html function are for taking an html string and escaping certain characters. escape_html will escape ampersands, brackets and quotes to their HTML/XML entities. This is useful to sanitize user content before displaying this on a template. js_escape_html is used for passing javascript information from a js template to a javascript function.

escape_html('<hello>&<goodbye>') # => &lt;hello&gt;&amp;&lt;goodbye&gt;

There is also an alias for escape_html called h for even easier usage within templates.

Format helpers also includes a number of useful text manipulation functions such as simple_format, pluralize, word_wrap, and truncate.

simple_format("hello\nworld") # => "<p>hello<br/>world</p>"
pluralize(2, 'person') => '2 people'
word_wrap('Once upon a time', :line_width => 8) => "Once upon\na time"
truncate("Once upon a time in a world far far away", :length => 8) => "Once upon..."

These helpers can be invoked from any route or view within your application.

The list of defined helpers in the ‘format helpers’ category:

  • simple_format(text, html_options)

    • Returns text transformed into HTML using simple formatting rules.

    • simple_format("hello\nworld") => “<p>hello<br/>world</p>”

  • pluralize(count, singular, plural = nil)

    • Attempts to pluralize the singular word unless count is 1.

    • pluralize(2, 'person') => ‘2 people’

  • word_wrap(text, *args)

    • Wraps the text into lines no longer than line_width width.

    • word_wrap('Once upon a time', :line_width => 8) => “Once uponna time”

  • truncate(text, *args)

    • Truncates a given text after a given :length if text is longer than :length (defaults to 30).

    • truncate("Once upon a time in a world far far away", :length => 8) => “Once upon…”

  • escape_html (alias h and h!)

    • (from RackUtils) Escape ampersands, brackets and quotes to their HTML/XML entities.

  • relative_time_ago(date)

    • Returns relative time in words referencing the given date

    • relative_time_ago(2.days.ago) => “2 days”

    • relative_time_ago(5.minutes.ago) => “5 minutes”

    • relative_time_ago(2800.days.ago) => “over 7 years”

  • time_in_words(date)

    • Returns relative time in the past or future using appropriate date format

    • time_in_words(2.days.ago) => “2 days ago”

    • time_in_words(100.days.ago) => “Tuesday, July 21”

    • time_in_words(1.day.from_now) => “tomorrow”

  • js_escape_html(html_content)

    • Escapes html to allow passing information to javascript. Used for passing data inside an ajax .js.erb template

    • js_escape_html("<h1>Hey</h1>")

See the wiki article for additional information: <…WIKI…>

Render Helpers

This component provides a number of rendering helpers making the process of displaying templates a bit easier. This plugin also has support for useful additions such as partials (with support for :collection) for the templating system.

Using render plugin helpers is extremely simple. If you want to render an erb template in your view path:

render :erb, 'path/to/erb/template'

or using haml templates works just as well:

render :haml, 'path/to/haml/template'

There is also a method which renders the first view matching the path and removes the need to define an engine:

render 'path/to/any/template'

It is worth noting these are mostly for convenience. With nested view file paths in Sinatra, this becomes tiresome:

haml :"the/path/to/file"
erb "/path/to/file".to_sym

Finally, we have the all-important partials support for rendering mini-templates onto a page:

partial 'photo/_item', :object => @photo, :locals => { :foo => 'bar' }
partial 'photo/_item', :collection => @photos

This works as you would expect and also supports the collection counter inside the partial item_counter

# /views/photo/_item.haml
# Access to collection counter with <partial_name>_counter i.e item_counter
# Access the object with the partial_name i.e item

The list of defined helpers in the ‘render helpers’ category:

  • render(engine, data, options, locals)

    • Renders the specified template with the given options

    • render ‘user/new’'

    • render :erb, ‘users/new’, :layout => false

  • partial(template, *args)

    • Renders the html related to the partial template for object or collection

    • partial 'photo/_item', :object => @photo, :locals => { :foo => 'bar' }

    • partial 'photo/_item', :collection => @photos

See the wiki article for additional information: <…WIKI…>

Admin Dashboard and Authentication (padrino-admin)

Overview

Padrino has a beautiful Admin, with these fatures:

Orm Agnostic

Adapters for datamapper, activerecord, mongomapper, mongoid

Template Agnostic

Erb and Haml Renderer

Authentication

Support for Account authentication, Account Permission managment

Scaffold

You can simply create a new “admin interface” simply providing a Model

Admin Usage

Create a project:

$ padrino-gen project fun-test
$ cd fun-test

For create the admin application:

fun-test$ padrino-gen admin

Now follow admin instructions so:

  • edit your config/database.rb

  • run padrino rake dm:migrate # or ar:migrate if you use activerecord

  • run padrino rake seed

Your admin now is “complete”, you can start your server with padrino start and point your browser to /admin!

For create a new “scaffold” you need to provide only a Model for them like:

fun-test$ padrino-gen model post --skip-migration # edit your post.rb model and add some fields
fun-test$ padrino-gen rake dm:auto:migrate
fun-test$ padrino-gen admin_page post
fun-test$ padrino start # and go to http://localhost:3000/admin

That’s all!!

Admin Authentication

Padrino Admin use a model Account for manage role, membership and permissions.

Scenario Ecommerce

For an ecommerce we usually deny some controllers/actions like

class MyEcommerce < Padrino::Application
  enable :authentication
  enable :store_location
  set    :login_page, "/login"

  access_control.roles_for :any do |role|
    role.protect "/customer/orders"
    role.protect "/cart/checkout"
  end
end

In this example if we visit urls that start with /customer/orders or /cart/checkout we will be redirected to our :login_page “/login”. Once we are correctly logged in we can visit these pages.

Scenario Admin

Suppose that you need to some actions for admin accounts and others for editors

When you generate padrino-admin will be created for you an Account model that have a role attribute. So:

class Admin < Padrino::Application
  enable :authentication
  disable :store_location
  set :login_page, "/admin/sessions/new"

  access_control.roles_for :any do |role|
    role.protect "/"
    role.allow "/sessions"
  end

  access_control.roles_for :admin do |role|
    role.project_module :settings, "/settings"
  end

  access_control.roles_for :editor do |role|
    role.project_module :posts, "/posts"
    role.project_module :categories, "/categories"
  end
end

In this case we protect the entire admin (all paths that start with “/”) except paths that start with /sessions so an unauthenticated user can login.

If we login as admin (account.role == ‘admin’) we have access only to paths that start with /settings.

If we login as editor (account.role == ‘editor’) we have access only to paths that start with /posts and /categories

Simple Mailer Support (padrino-mailer)

Overview

This component uses an enhanced version of the excellent pony library (vendored) for a powerful but simple mailer system within Padrino (and Sinatra). There is full support for using an html content type as well as for file attachments. The MailerPlugin has many similarities to ActionMailer but is much lighterweight and (arguably) easier to use.

Usage

Let’s take a look at using the MailerPlugin in an application. By default, MailerPlugin uses the built-in sendmail functionality on the server. However, smtp is also supported using the following configuration:

 Padrino::Mailer::Base.smtp_settings = {
   :host   => 'smtp.gmail.com',
   :port   => '587',
   :tls    => true,
   :user   => 'user',
   :pass   => 'pass',
   :auth   => :plain
}

Once those have been defined, the default will become smtp delivery unless overwritten in an individual mail definition. Next, we should define a custom mailer extended from Padrino::Mailer::Base.

# app/mailers/sample_mailer.rb
class SampleMailer < Padrino::Mailer::Base
  def registration_email(name, user_email_address)
    from 'admin@site.com'
    to user_email_address
    subject 'Welcome to the site!'
    body    :name => name
    type    'html'                # optional, defaults to plain/text
    charset 'windows-1252'        # optional, defaults to utf-8
    via     :sendmail             # optional, to smtp if defined otherwise sendmail
  end
end

This defines a mail called ‘registration_mail’ with the specified attributes for delivery. The body method is passing the name attribute to the body message template which should be defined in [views_path]/sample_mailer/registration_email.erb as shown below:

# ./views/sample_mailer/registration_email.erb
This is the body of the email and can access the <%= name %> that was passed in from the mailer definition
That's all there is to defining the body of the email which can be plain text or html

Once the mailer definition has been completed and the template has been defined, the email can be sent using:

SampleMailer.deliver(:registration_email, "Bob", "bob@bobby.com")

or if you like the method_missing approach:

SampleMailer.deliver_registration_email "Bob", 'bob@bobby.com'

And that will then deliver the email according the the configured options. This is really all you need to send emails. A few variations are shown below for completeness.

If we want to attach files to our email:

# app/mailers/sample_mailer.rb
class SampleMailer < Padrino::Mailer::Base
  def attachment_email(name, user_email_address)
    from 'admin@site.com'
    to user_email_address
    # ...
    attachments { "foo.zip" => File.read("path/to/foo.zip"), "file.txt" => "this is a text file!" }
  end
end

or perhaps we want to have a short body without the need for a template file:

# app/mailers/sample_mailer.rb
class SampleMailer < Padrino::Mailer::Base
  def short_email(name, user_email_address)
    from 'admin@site.com'
    to user_email_address
    subject 'Welcome to the site!'
    body    "This is a short body defined right in the mailer itself"
  end
end

See the wiki article for additional information: <…WIKI…>

Painless Page and Fragment Caching (padrino-cache)

Not implemented yet.

Copyright © 2010 Padrino. See LICENSE for details.