Controllers and Actions

Ejscript controllers manage the application and respond to client requests. They are the conductors of the application and orchestrate the application's activities.

Processing Flow

Ejscript controllers process requests in stages:

  1. Decode the URI and web request
  2. Route an incoming request to the appropriate controller
  3. Invoke the requested action
  4. Access and update the application state
  5. Render a response view to the client

When a request is received, Ejscript will parse and decode the request before routing to the appropriate Controller where it will create an instance of the controller class and invoke the requested action method.

Anatomy of a Controller

So what does a controller look like?

public class CartController extends ApplicationController {
    public var product: Product
    action function index() { 
        renderView("list")
    }
    action function create() {
        product = new Product
        renderView("edit")
    }
    action function edit() {
        /* Read a product from the database */
        product = Product.find(params.id)
    }
    action function list() { 
        /* Will render list.ejs by default */
    }
    action function update() {
        product = Product.find(params.id)
        /*  Update the product based on user input */
        if (product.saveUpdate(params.product)) {
            inform("Product updated successfully.")
            redirect("list")
        }
    }
}

This is a simplified controller — definitely not production code as it does not validate user input. This controller provides five actions which are decorated by an action qualifier. This qualifier makes a JavaScript function visible as a controller action method.

If the client issues a request for:

https://embedthis.com/myApp/cart/create

The create action will be invoked. It will create a new product and then render the edit.ejs view back to the client.

Actions

Actions are where the controller does its work. In Ejscript, actions are simple JavaScript functions prefixed with an action qualifier. They don't need to be registered or otherwise configured before use. When Ejscript receives a request from the client, it will parse the request and invoke the request action specified in the URL.

When a request is received, the controller framework looks for an action method of the required name. If one is not found, it invokes the missing action method which renders a default error message back to the client.

Controller Context

Ejscript establishes a request context for the controller before invoking the action. This consists of the following objects which are visible to actions:

The controller can add to this context by declaring public variables in the controller class or the ApplicationController which is the base class for all controllers. Views can automatically access any such public controller variables.

Processing the Request

The action method can perform any processing it desires. There are no real restrictions except you don't want to block for too long without giving the client some feedback.

Actions often retrieve a database record via the Model and store an object representing the model in a public variable for easy access by the view. NOTE: the controller is not persistent across client requests.

Model Data

Ejscript provides an Object Relational Mapping (ORM) layer for accessing database data via convenient JavaScript objects. The ORM layer is a collection of database Model classes for the application. controllers use this layer to access the database via these Model classes. A typical paradigm is for action methods to read a database record and store the record in a public controller property. The view can then simply access the database data via this property.

For more details, please see Database Models.

Form Data

HTTP Form data is marshalled by Ejscript into the params object which is accessible to actions. Each HTML input element posted by the client will become a property of params. Ejscript can also organize form data into nested objects. If an input element name contains a period, then Ejscript will create nested objects to match the input element name.

Rendering Views

After processing the request, the controller is responsible for rendering a view back to the client. If the action method does not explicitly render a view, Ejscript will look for a view with the same name as the action method.

In the prior example, the edit action did not call any render function, so the framework will look for, and if found, run a view views/cart/edit.ejs.

Generating Controllers and Actions

Ejscript includes an an application generator, called mvc to make it quick and easy to create controllers, actions and controller scaffolds. To generate a new controller, run:

mvc generate controller NAMES...

NAMES... are the names of the controllers you want to generate. This command will create controller source files under the controllers directory. Each controller will contain an empty controller class with an empty index action function. You can edit the controller source to meet your needs.

When you create a controller, you can also (optionally) generate a set of named action functions. To generate actions when you create a controller, run:

mvc generate controller NAME ACTIONS...

If ACTIONS are provided, action functions and views pages will be created for the given names.

Generating Scaffolds

A scaffold is a generated set of actions and views that provide add, edit, and list functionality for a database model. Scaffolds are useful to quickly generate prototype web pages and actions for managing a database table. To generate a scaffold:

mvc generate scaffold MODEL [field:type ...]

When creating a scaffold for a database model, mvc will create a database model, database migration, controller and edit and list view pages.

If field:type pairs are supplied, the database migration will include code to create a column for each specified field of the requested type. The valid database types are: binary, boolean, date, datetime, decimal, float, integer, number, string, text, time, timestamp.

The scaffold will include an edit action and view that provides add and edit capability. The list action and view, provides the ability to list the database table rows and select an entry to edit.

Controller Class

The Controller class has a large set of methods and properties. See the Ejscript Library for full details. Some of the more important properties:

Property Description
actionName Name of the action method being run.
application Application global data.
controllerName Name of the controller method being run.
flash Lower case name of the controller.
flash Flash message object for the next view.
host HTTP host object.
params Form parameters object.
request HTTP request object.
response HTTP response object.
session Session state information.

The controller class provides the following methods:

Method / Property Description
cache Add a cache-control HTTP header.
createSession Enable session control.
destroySession Destroy a session.
discardOutput Discard all prior buffered output.
error Send an error response back to the client.
escapeHtml Transform a string to be safe for output in a HTML web page.
html HTML encode the arguments.
inform Send a positive notification to the client in the flash area.
makeUrl Make a URL suitable for invoking actions.
redirect Redirect the client to a new URL.
render Render the raw arguments back to the client.
renderFile Render a file's contents back to the client.
renderRaw Render raw data.
setCookie Define a cookie to include in the response.
statusMessage Send a status message to any registered view controls.
unescapeHtml Transform an escaped string back to its original contents.
warn Send a warning message to the client in the flash area.
write Write text back to the client.
writeHtml Write HTML escaped data back to the client.

Filters

Filters enable a controller to perform processing before and after actions are run. Filters are useful to do authentication and logging. Filters run in the same context as an action method and can access the controller instance and the Request, Response, Http, session and flash objects.

To run a filter before the action method, use the beforeFilter method. This should be run in the constructor for the controller. For example:

public class TaskController extends BaseController {
    function TaskController() {
        beforeFilter(authorize, { except: "login"})
    }
    private function authorize() {
        if (params.username != "goodname" && params.password != "abracadabra") {
            error("Invalid Login")
            redirect("login")
        }
    }

This will cause the authorize to run before any action method except for the login action. The authorize function can test the user name and password and if not authorized, it can fail the request and redirect the user back to the login page. Filters can be run after the request by using the afterFilter method.

The filter methods take an options object as the second parameter. Two option properties are defined:

When specifying the argument to except and only, you can provide either a single action name as a string or an array of action names.

© Embedthis Software, 2003-2015. All rights reserved.