Kiss A simpler, smarter web application framework for Ruby

Actions

SECTIONS
What an Action Looks Like User Input Nested Actions Missing Action Files Default Action Name Forced Rendering Redirection Action Class Hierarchy Persistent Session Data Login Session Data User Authentication Database Access

What an Action Looks Like

In the previous chapter, we created a new Kiss application. Now let's add an action to it.

Inside your application directory, find the directory named actions and open it. Create a text file named test.rb, and add the following code to it:

def call
  set :favorite_color => 'red'
  set :favorite_fruit => 'apple'
  set :favorite_framework => 'Kiss'
end

After the method ends and returns, a corresponding template will be rendered. Let's create the template file named test.rhtml, also inside the actions directory:

<p>Your favorite color is <b><%= data.favorite_color %>.</b></p>
<p>Your favorite fruit is <b><%= data.favorite_fruit %>.</b></p>
<p>Your favorite Web application framework is <b><%= data.favorite_framework %>.</b></p>

Now point your web browser to: http://localhost:4000/test 

As you can see, Kiss took the data set in the action code and inserted it into the template. So how did that work, exactly?

  1. The request to http://localhost:4000/test tells the Kiss framework that we want to run the /test action.
  2. The Kiss framework finds the corresponding action file test.rb inside the actions directory, loads it, and calls the call method.
  3. The call method sets some output data for the template. Note: Instead of using the set :key => value command syntax, we could also say: data.favorite_color = 'red'
  4. After completion of the call method, Kiss looks for a template with the same name as the action. It finds the file test.rhtml in the actions directory.
  5. The template file is loaded, interpreted, and rendered to generate the final output, which gets sent back to the user's web browser.

What if red isn't your favorite color? Just change the favorite color string in your action code, reload the page in your browser, and watch how the output changes to match what you entered.

User Input

Parameters

Let's make another action to do some math. Create a file named add.rb in the actions directory, with this code:

def call
  set :sum => params['a'] + params['b']
end

Then create a template add.rhtml in the same directory:

<%= params.a %> + <%= params.b %> = <%= data.sum %>

Now point your web browser to: http://localhost:4000/add?a=2&b=3 

You should see the solution: 2 + 3 = 5

Did you notice the input parameters in the URL? We gave our action two numbers to add, a=2 and b=3. If we edit the URL to set a=205 and b=347, then we'll get a new solution: 205 + 369 = 574. Thus we see how Kiss can respond to different inputs.

We can also send input to a Kiss action from an HTML form, using either the GET or POST method. The GET/POST parameters will be stored in the params hash.

Arguments

We can also pass input to actions by adding them as part of the action path in our request URL. We could change our /add action above to make the request syntax cleaner, like this: http://localhost:4000/add/205/369 

Now the numbers are part of the action path URL. When Kiss receives this request, it figures out that we want to run the /add action and pass in the numeric arguments 205 and 369. These arguments are stored in an array named args. Let's change our add.rb file accordingly:

def call
  set :sum => args[0] + args[1]
end

And also change the template file add.rhtml:

<%= args[0] %> + <%= args[1] %> = <%= data.sum %>

Now load this URL in your web browser: http://localhost:4000/add/205/369 

You should see the same result as before: 205 + 369 = 574. The only difference is that our URL syntax is a little cleaner.

Forms

Kiss provides a library for creating self-validating forms that render their own HTML  and connect to database models to read and store data. Learn more about it in the Forms chapter.

Nested Actions

You can create subdirectories within the actions directory and add action files inside them. For example, create a directory named sub in the actions directory, and move the test.rb and test.rhtml files into sub.

Then point your browser to:

http://localhost:4000/sub/test 

Kiss will find and run the /sub/test action, located at actions/sub/test.rb.

Missing Action Files

If you request an action path that does not have a corresponding Ruby action file, Kiss will skip action execution and look for a template instead, of the same name as the requested action. If it finds the template, it will interpret it, but any output data values inserted in the template will be blank, since no action code was run to set them. If it doesn't find a template, then Kiss will raise a FileNotFound error.

Default Action Name

If you don't specify an action name in your request, Kiss will look for the default action name, index.

When you go to http://localhost:4000/, Kiss looks for actions/index.rb but doesn't find that in our application. Then it looks for the template actions/index.rhtml, finds that file, and renders it to the web browser.

If you go to http://localhost:4000/sub/, Kiss looks for actions/sub/index.rb but doesn't find it, then looks for the template actions/sub/index.rhtml but doesn't find that either. So Kiss raises a FileNotFound error.

Forced Rendering

The render method forces Kiss to end the execution of the action code and render output immediately.

By default, Kiss looks for a template of the same name as the action. However, you can specify a different template name by passing it in, like this: render :template => 'my_template.rhtml' 

Redirection

redirect_action( action_path )

Stops action execution and outputs an HTTP response with a Location header to redirect the browser to another action, specified by action_path. For example, try adding this to your /sub/test.rb action:

redirect_action('/index')

Now when you go to http://localhost:4000/sub/test, your browser will be redirected to: http://localhost:4000/index

redirect_url( url ) 

Works like redirect_action, except that it redirects to the complete URL specified by url, which can be outside your application.

Action Class Hierarchy

Each action file becomes its own class, with its own namespace. This allows you define other methods in your action files besides the main call method, and not worry about method name conflicts with other actions.

Each actions directory also gets its own class, from which the actions inside the directory are subclassed. You can define methods in the directory class in a file named _action.rb inside the directory. Any methods defined in this file will be available to actions within the same directory or any subdirectories.

You can create an _action.rb in each action subdirectory, to define additional methods just for that subdirectory and its contents. Kiss automatically creates an action class hierarchy from the root Kiss::Action class through each directory on an action path to the action file's class. For example, here is the class structure for the action path /customer/3252/contact/23823/phone_numbers/add (each line is a subclass of the previous):

Kiss::Action
  /customer/_action.rb  (optional)
    /customer/contact/_action.rb  (optional)
      /customer/contact/phone_numbers/_action.rb  (optional)
        /customer/contact/phone_numbers/add.rb

You can create a deep, complex action class hierarchy, just by arranging your action files in nested directories and adding _action.rb files as needed.

Persistent Session Data

You can save data to a persistent store by setting values in the session object:

session.username = 'bob123'

At the end of action processing, Kiss will save the session data back to its persistent data store. To set up a persistent data store, you must use the session_class configuration directive (see the Config chapter).

Kiss will send a cookie to the user's web browser, which will be used to reload the session data for you automatically on each subsequent request by the same user, until the cookie expires.

Login Session Data

The login object contains data specific to a login session, which may expire after a short time period, before your application's cookie expires. This is the place to store information about the currently logged-in user, such as user ID:

# on action login.rb, after verifying user's password...

login.persist(:user_id => user.id)
login.expires_in( 30.minutes )
login.user = user

The login.persist method sets the user_id value to last until the login object expires, which will be 30 minutes from now. The last statement makes the login.user value available to action and template code for this request only. (Database objects don't serialize very well to session data stores, so we have to reload this using login.user_id on each request.)

User Authentication

Kiss supports automatic site-wide user authentication via a configuration setting. All you have to do is provide an authenticate method in your root actions directory class (actions/_action.rb), and a set of login, logout, and user registration actions. Then your authenticate method will check whether there is a valid login session by looking for data in the login object. If it's valid, authenticate should load any temporary data for this request (such as login.user from login.user_id). If there is not a valid login session, authenticate should redirect to your login.rb action.

See the Config chapter for more information on site-wide user authentication.

Database Access

It would be really helpful at this point to talk about how to access a database. Let's proceed to the chapter on Database Models.