Chapter 3. Controllers

In Merb, controllers are what tie all of your application code together. They are the C in MVC and have been built to assemble responses to the requests received from users. On occasion, a controller’s response is entirely produced by code in the controller itself. More often, though, responses are complex composites that incorporate the pulling of data through models and the rendering of views through templates.

Controllers also handle the more subtle aspects of responses, including response format, MIME type, and status code. We’ll also craft within them behind-the-scenes logic that uses sessions, filters, and exceptions. When users request unavailable or impermissible data, controllers can redirect those users to more appropriate locations. Finally, Merb controllers come with the built-in ability to queue up background processes and run them outside the standard request-to-response cycle.

In this chapter we will go over each of these topics as well as controller internals. While doing this, we’ll emphasize controllers themselves and defer examples involving models and views to later chapters. This may seem unconventional, but separating these concerns will, if nothing else, make this chapter an invaluable reference when all you need to do is cut to the chase. That said, there will be some blurring of focus near the end of this chapter as it weaves into the next and we discuss the rendering of views through controllers.

If you’re completely new to MVC, controllers are definitely the most natural and best place to start, because they let you dig right in and produce responses from the get-go. To keep things simple, nearly all the examples in this chapter are going to be single-file Merb applications that can be run easily alongside a default set of routes.

3.1 From request to controller

Since we previously went over the Merb router, it’s a good time to walk through how requests get to controllers and how controllers set up actions to handle those requests.

3.1.1 A simple application

While Merb controller actions are just standard methods of classes you can initialize and use, a Merb application itself does not call these actions. Instead, Merb initializes controllers based upon requests and then uses the controller method _dispatch to call the appropriate action. Notice that _dispatch starts with an underscore. As an application developer you don’t really need to know about it, but by using it you will avoid conflicts in the namespace of application-specific controller methods. However, we mention it here because of its central role in how controller instances deal with requests.

That said, a basic understanding of both Merb::Request and _dispatch is desirable. So let’s fire up interactive Merb with the following application and imitate a request from the browser:

image

3.1.2 How requests get dispatched

When a Merb::Request is initialized, it requires at least two options to make sure it gets routed correctly: REQUEST_PATH and REQUEST_METHOD. True to their names, these two options represent the path and the method of the request.

Let’s make a series of requests and observe their responses. To do this, we’ll use the Merb::Request#handle, which uses the router to first determine the appropriate controller and its action and then dispatch the request. Because we’re interested only in the body of the response, we’ll tack that onto our statement.

image

The second request we created used QUERY_STRING. Again, as an application developer, it’s not essential for you to know about the options that define a request, but QUERY_STRING, had it come from a browser, would be the text that follows the question mark in a URL such as http://localhost:4000/hello_friend?name=you. The end effect, with respect to the controller, is the setting of params[:name] equal to 'you'.

3.1.3 The controller’s perspective

Let’s imitate another aspect of request handling by creating the controller ourselves instead of using Merb::Request#handle. We won’t need REQUEST_PATH and REQUEST_METHOD, since in this example we’ll be doing the job of the dispatcher and router ourselves when we choose and initialize the appropriate controller and then invoke the right action:

image

Notice that this does not return a full response as in the previous examples but instead simply the body. This is because the job of each controller action is simply to return the body for the response. As we’ll discuss later on, the body can be more complex than a string and may use view template rendering through the method Merb::Controller#render.

Aside from the body, the remainder of the response is typically set through various side effects of the controller code. To replicate the full response in interactive mode, we can more closely follow the path that the dispatcher takes and invoke the handling of a request with the Merb::AbstractController#_dispatch method we spoke of earlier:

image

The second line initializes the HelloFriend controller. Notice how it requires a request as part of initialization. This is essential, as it allows the controller object to be aware of the request it is handling and interpret its parameters. Finally, we use _dispatch(:index) to indirectly perform the index action, and body to give us only the body of the return. There are two other major concerns that _dispatch takes care of, sessions and filters, both of which we will discuss later on.

3.2 The controller classes

All controllers in Merb inherit from the class Merb::AbstractController. This class was designed to allow the Merb core to be as extensible as possible. This is because, despite the fact that MVC and web frameworks now seemingly go hand in hand, the concept of the controller can apply well outside the web request controller. For example, sometimes you’ll want a controller class to manage the sending of emails. Other times, reminiscent of the original inspiration for the MVC design pattern, you’ll want a controller to determine the behavior of a particular widget embedded in the context of a response’s larger view template. Both of these are possible thanks to Merb’s abstract controller.

At this point, if you feel a bit lost with regard to abstract controllers, don’t worry. What’s important to know right now is that all Merb controllers are actually subclasses of either Merb::AbstractController or one of its descendants. Within the Merb core, these descendants are Merb::Controller, Application, and Exception. Interestingly enough, these three classes, in the order in which they were just listed, form a descending chain of subclasses. In other words, Exception is a subclass of Application, which is a subclass of Merb::Controller, which itself is a subclass of Merb::AbstractController. We’ll go over each of these in this section and then describe how to use them in the rest of the chapter. In later chapters we’ll also see two more subclasses of Merb::AbstractControllerMailController and PartController—both of which exemplify the ability of Merb::AbstractController to be subclassed in different ways for extremely practical purposes.

However, before we get into these specific controller classes and their methods, it’s important to know that many of the methods you’ll find in the source of each of these classes begin with an underscore. This is because Merb controller classes seek to avoid populating themselves with method names you may otherwise want to use. Additionally, methods that start with underscores are understood to be outside the scope of the Merb public API and therefore don’t really need the attention of the application developer. With all this in mind, please note that we are simply enriching your understanding of the framework internals.

Finally, you should know that some controller instance methods are called actions. This is because they are responsible for the act of responding to requests. In general, if you’re wondering whether a method is available as an action or not, you should first check if it is a public instance method. If it is, then it’s probably an action. There is, however, one exception, and that’s if the method has been added to the list of nonaction methods. This list is maintained so that you can prevent users of your application from sending requests directly to these methods. Not so surprisingly, most public instance methods in the core controller class appear in this list.

3.2.1 The abstract controller

Despite being the eldest parent class of all controllers, Merb::AbstractController makes very few specific demands on its descendants, leaving most of its methods as nothing more than stubs. Ultimately this means that Merb::AbstractController, true to its name, acts more as an ideal form of what a controller should look like than anything else. Let’s go over the prototypical methods that have been included in Merb::AbstractController. First we’ll look at class methods and then instance methods.

3.2.1.1 Class methods

There aren’t many API class methods in Merb::AbstractController, but those that do exist well characterize what a controller is all about. They also give you an idea of what sort of attributes and logic can be applied throughout a controller class and across actions. In Tables 3.1, 3.2, and 3.3, we’ve divided the class methods into general methods, filter methods, and render methods.

Table 3.1 General methods

image

Table 3.2 Filter methods

image

Table 3.3 Render methods

image

3.2.1.2 Instance methods

There are more API instance methods than class methods when it comes to Merb::AbstractController. Here we’ve divided them into general methods, URL methods, and view methods, as shown in Tables 3.4, 3.5, and 3.6. We’ve spoken before of using Merb outside web development, but the inclusion of URL methods in the abstract controller really pivots Merb use toward the web framework.

Table 3.4 General methods

image

Table 3.5 URL methods

image

Table 3.6 View methods

image

3.2.2 The Merb controller

All Merb controllers inherit from the class Merb::Controller. This controller fully implements the web functionality for controllers. Therefore, it’s here that we’ll find the inclusion of request, parameter, and header methods. The API methods are broken down into class methods and instance methods; let’s go over these newly added methods.

3.2.2.1 Class methods

The Merb::Controller class methods mainly serve to define what methods are available as actions and what formats are provided by those actions. Consequently, we’ve divided the methods introduced by the Merb::Controller into general and format methods, shown in Tables 3.7 and 3.8.

Table 3.7 General methods

image

Table 3.8 Format methods

image

3.2.2.2 Instance methods

The instance methods of Merb::Controller serve a number of purposes, most notably the need to make request and session data accessible to the action code. Other methods exist simply to aid in formatting. Tables 3.9 through 3.13 cover the most common API methods.

Table 3.9 General methods

image

Table 3.10 Session methods

image

Table 3.11 Format methods

image

Table 3.12 Escaping methods

image

Table 3.13 Other methods

image

3.2.3 The application controller

If you create a standard Merb application with merb-gen, you will find two files in app/controllers/. The first of these, Application, is meant to serve the parent class of all the application’s other controllers. This allows you to centralize shared code that would otherwise be found across your application’s controllers. For instance, here we have placed a filter that ensures that all web requests come from logged-in users:

image

3.2.4 The exceptions controller

The other controller generated as part of a Merb application is the exceptions controller. It is subclassed from Application and is used to craft error responses you may have already encountered during development. Note that it is common to extend or override the default responses. So, for instance, below we have created a new controller action that handles unauthenticated users.

image

3.2.5 Other controllers

As previously mentioned, Merb::Controller is not the only subclass of Merb::AbstractController. In later chapters we’ll see the Merb::MailController and Merb::PartController, each of which controls the flow of logic with actions without directly handling web requests.

3.3 Custom controller classes

Now that we have described the various core controller classes as well as followed the pathway through which a request is handled, this is a good time to create our own controllers.

3.3.1 Controller location

In the standard Merb application layout, all web controllers are located within the directory app/controllers/. We say all web controllers because the other controllers, MailController and PartController, tend to live elsewhere in other directories. However, if you’re using the flat layout, you’ll find that all of your controllers are kept in one file, application.rb. Also, in the case of the very flat layout, your controllers basically have nowhere else to live but as part of a single file. Note that both the flat and very flat layouts are generated with a custom controller subclassed directly from Merb::Controller instead of Application. This seems to be based on the assumption that you’ll be making an application small enough that it does not need a parent class for all controllers. However, don’t let that restrict you—if you’re using the flatter layouts and need Application or Exception, by all means, code them in.

Even though it’s extremely rare to see someone deviate from the default locations, you can change the location of your controllers if you want. To do this, you can define a framework hash for Merb::Config inside the file config/framework.rb. This alters the default framework locations at Merb boot-up, but make sure you mention all locations you want to be set, because framework.rb doesn’t merge with the default settings. The following snippet shows, among other things, how to set the location of controllers to controllers/ as opposed to app/controllers:

image

To check that this has had an effect or just to find out where your application thinks controllers should be, you can always fire up interactive Merb and have it evaluate the following:

image

3.3.2 Naming controllers

By convention, the filename of a controller file should be the snake case of the contained controller’s class name. For example, a controller named OrderTransactions would be contained in a file named order_transactions.rb. This isn’t strictly necessary, but it’s good practice and a convention that others can recognize. As long as your controllers are located within the controller directory or one of its subdirectories, they will be loaded at boot.

Feel free to name each controller whatever you’d like, but keep in mind that the names of controllers could collide with other class names in the global namespace. This specifically becomes a problem with models. Consequently, the convention is to name controllers that have corresponding models in the plural form. For example, you’ll often find a controller named Users when there’s a model named User. If there is no corresponding model, don’t worry; just name your controller whatever makes the most sense. Welcome and Home are good examples of names for a controller that would handle the landing page of your application.

3.3.3 Organizing controller methods

The organization of a controller’s methods is critical to how a controller responds to requests. In general, you should define one public instance method for each type of request a controller will handle. If you need other methods that won’t handle requests directly, you should leave them for near the end of your controller and mark them either private or protected. Both private and protected, in the context of Merb controllers, have the same effect, as it would be odd to have two Merb controller instances working together during a single request. Typically, you use private or protected methods in your controller classes because they allow you to

• Share a nonaction method among controller actions

• Make methods available to all controller subclasses

• Increase the readability of code within your controller

3.3.3.1 Sharing a nonaction method

In this fabricated example we use a private method as a means of accessing data:

image

In our model-less world of controller-only applications this makes sense. However, more realistically, such a method would most likely encapsulate several lines of data, retrieving code that would otherwise appear in multiple controller actions. A perfect example of this is the case of the show and edit methods of a RESTful resource.

3.3.3.2 Making methods available to subclasses

Sometimes you want to make a method available to more than one controller. The most typical way of doing this is to make it a private method within the Application class:

image

This highly contrived example shows us using a private method in Application to retrieve a hash of information. After we go over more Merb functionality like models and filters, the practical use of parent private methods will become clearer. For now, recognize that it is a clean way to organize controller code.

3.3.3.3 Increasing readability of an action

Often a controller action can get lengthy and hard to read. But by moving lines of code into private methods, we can increase readability with clear names. The following example shows how an action can be arranged in an understandable way even if all functionality is not in place:

image

3.3.4 Setting callable actions

Merb::Controller and its descendants were created to directly handle requests. Thus by convention, all public instance methods are callable actions, but if you’re constructing your own variant of the Merb controller, you may need a public method that isn’t available to be called as an action. For example, the Merb::Controller class has the following public methods but has hidden them from being called as actions: request, headers, status, and rack_response. This is because all of these methods are used to manipulate a controller instance in the larger context of sending back a response and thus must be made public.

3.3.4.1 Hiding an action

In case you too want to come up with a public method that’s best to hide, you can easily do so by using the hide_action class method within your controller class:

image

3.3.4.2 Showing an action

Likewise, you can show an action that was previously hidden using the show_action class method. This applies to subclasses of controllers with hidden actions.

image

3.4 Filters

Often you want to call a method before or after the performance of a controller action. Filters allow you to do so for multiple actions without having to explicitly evoke the relevant method in each action. Typical examples of filters include authentication, resource checking, and application auditing. Filters conventionally appear at the top of a controller and take either a method name or a Proc. An optional hash can specify to which actions the filter should apply. Multiple filters can apply to a single action and are executed as part of a filter chain. It’s good to know that filters are available to all controller classes descending from AbstractController, including MailController and PartController.

3.4.1 Before filters

Before filters are called before any of the action code has been executed. They are created using the before class method, which is available to all descendants of AbstractController. The first parameter of before can be either a method name or a Proc. Method names may be in the form of strings but are typically symbols. Thus, all of the following filters are equivalent:

image

Note, however, that a before filter specified by the same method name overrides previous before filters in the before filter chain. Consequently, if you actually used the code shown above in a controller, authorize would be called only twice.

The method called by a before filter is typically a private or protected method of the controller, and you will often see filters appearing as follows:

image

You should know that Merb filters are evaluated in the context of the controller object. Thus, when your before filter is in the form of a Proc, you are able to set instance variables to be used later on:

image

Before filters are also able to catch :halt exceptions, which is useful for redirecting or diverting unauthorized or incorrect requests:

image

3.4.2 After filters

An after filter can be created using the after class method of AbstractController. Similarly to before, it takes either a method name or a Proc, but it is evaluated after the performance of the action. The most typical use of an after filter is either to log the use of your application or to do cleanup or postperformance processing on resources:

image

You can make last-minute alterations to the response by accessing the @body attribute:

image

One thing to note with after filters is that the client does not receive a response until the after filter chain is complete. If you run the example below, you’ll end up waiting a random number of seconds for the actual response. If client response time is an issue, consider using Merb’s deferred instead, which is discussed near the end of this chapter.

image

3.4.3 Filter options

When you want a filter to be applied only to particular actions of a controller, you can do so by specifying them as an array of symbols keyed to :only in the option hash:

before :read_file, :only => { :show, :edit }

If instead you want a filter to not apply to particular actions of a controller, you can specify them as an array of symbols keyed to :exclude in the option hash:

before :authorize, :exclude => { :login }

Sometimes you want to have filters applied only in the case of more complex conditions. The :if and :unless options allow you to do this with either a method name or Proc:

image

You can also pass parameters to filters by using :with, but when doing so you’ll have to make sure that the arity of the filter matches the size of the :with array:

before :has_role, :with => ['Admin']

3.4.4 Skipping filters

On occasion you’ll want to skip a filter that was defined in a superclass. To do this, you can use the skip_before and skip_after class methods from AbstractController:

image

3.5 Redirects

There are many cases when a user has sent a request that should ultimately get redirected. You can make this happen by using the controller method redirect. The redirect method accepts a string for a URL as its first parameter and also takes an optional hash. This optional hash may include a Boolean setting of :permanent and a :message to pass on:

image

3.5.1 A redirect caveat

One important point to remember when using redirects is that they do not stop the execution of the controller action, and whatever code is left to evaluate will run before the redirect is sent. The controller action, however, will not get the chance to return a value. The following example should make this clear:

image

In the previous example, "Here comes another winner!" is logged, but because of the redirect, which is essentially a change in management for the final response, none of us gets our F355. This example is harmless enough for both user and developer, but you should be cautious when using redirects and make sure that unnecessary business logic does not run.

Another thing to note in this example is the use of :permanent in the second redirect. This effectively changes the status code of the response from 301 to 302 and from the browser’s perspective assures that '/show_prize' should always point to '/apologize'.

3.5.2 Redirects after POST requests

The most common use of redirects in practice is to redirect users after they have posted content. You may not be familiar enough with Merb to completely understand the following example, but here a user has posted what looks like a new entry of some sort, and if it saves without error, the user is redirected to the list of entries:

image

3.5.3 Redirecting in before filters

At other times, controllers redirect users before the action ever starts. This most likely occurs because a particular resource doesn’t exist or because a user has yet to log in. Before filters are a great place for this kind of logic because these cases tend to apply to multiple controller actions and are simplified logistically by gaining access to the throwing of halts. Let’s take a look at an example:

image

An important takeaway from this example is how the redirect was accomplished. Before filters are able to catch thrown halts that can also take Procs. These Procs are evaluated using instance_eval. By putting a redirect in this Proc, we are able to redirect the controller without having to worry about more of the controller code being evaluated. Though it may seem redundant to mention, throw :halt does not work anywhere but inside the before filter chain, so don’t try to use it anywhere else or you’ll just get an uncaught exception and an error that looks like this:

~ uncaught throw `halt' in thread 0xd6bad0 - (ThreadError)

3.6 Exceptions

If you’re looking for something similar to throw :halt that you can use outside before filters, raising exceptions may be your answer. By raising particular controller exceptions, you can halt controller execution midway and internally reroute the request to the Exceptions controller. There’s one important thing to note, though: Unlike redirects, using Exceptions means it’s the end of the line for your user and an error page will be displayed. Yes, you’ll be able to make this error page pleasing and include a cute mascot, but ultimately it is an error page, so if you’re going to use it, make sure that’s what you intend and not a more subtle redirect.

3.6.1 Raising an exception

Many exceptions have already been defined for you within the Merb core. Let’s go through an example using one of the predefined exceptions to get a basic feel for how they are used:

image

Here, when we request the index, a Not Found error appears along with a 404 status code in the response.

3.6.2 Controller exceptions

When you raise an exception somewhere in your controller code, it is rescued by the dispatcher and redispatched to be handled as a controller exception. These exceptions are defined in the module Merb::ControllerExceptions and offer an exception for each of the W3C standard HTTP status codes.

If the error raised is not among these existing controller exceptions, Merb interprets it as an internal exception and uses the class InternalServerError to handle it. This is the error page you’ve seen in the past when something has gone wrong with your code.

3.6.3 The exceptions controller

The exceptions controller is one of the core controller classes we talked about earlier. Its purpose is to translate an exception into a response. Merb handles the routing behind the scenes, but what’s important to know is that each exception class name is snake-cased and then called as an action method name in Exceptions. Below we see a custom controller exception that, with the help of the exceptions controller, responds with a string.

image

If you request /root, the BadHacker exception will be handled in the same way as an unauthorized user. The only difference, of course, is the custom response found in the exceptions controller.

3.7 Rendering templates

Rendering templates is one of the most common actions you’ll find at the end of a controller. Consequently, there are a number of methods found in the Merb::Controller class that deserve our consideration now before the chapter on views (Chapter 4). We’ll go over each of these methods, but before we do, we’ll need to get comfortable with how Merb brings together controllers and templates.

3.7.1 How templates are compiled

Templates typically exist as files stored in app/views, all of which Merb opens up and inlines into a template method. These template methods are then accessible by original filename to any of the subclasses of Merb::AbstractController. Typically, a controller associates itself with a particular path, and then the action that calls render appends its name as a file followed by a response format extension and then a template format. For example, the action Users#index associates itself by default with the template at app/views/users/index.html.erb. The .html is there since HTML is the default format that Merb uses for responses. The .erb is for ERB, which is the default template format.

ERB is a versatile template type that has the potential to render HTML, XML, JSON, or really any textual format. However, there are other template engines that may be more suitable for particular responses. These alternatives include Haml, which excels in structuring HTML and XML with extreme brevity. For now, though, since we’re currently considering templates only in the context of controller logic and not in that of the view, we’ll use only ERB.

In fact, in order to keep with our desire to produce single-file Merb applications, we’re going to do something completely unconventional: We’re going to include our templates as virtual files. You will probably never do such a thing, but getting a good feel for how templates are compiled through imitation will definitely demystify what otherwise may seem like magic. Let’s start off with a simple example:

image

If you run the code above as a single-file application and check http://localhost:4000, you’ll find a friendly 'hi'. You’ll recognize that pulling this off wasn’t as easy as it was in the past. The first thing we did was add a Merb::BootLoader.after_app_loads block. As we saw in Chapter 1, this block runs after our application code has been loaded. Here we use it to first create a fake template using a virtual file and then inline that virtual file using inline_template. Notice that the virtual file takes two parameters for initialization. The first is what would have been the actual content of the file. The second is a fake file path. Here we’ve matched it to what the Weird#index method would naturally associate itself with.

Now let’s take a look at the content of the virtual file. You’ll notice some text, some odd bracketing, and a class method inside. We’ll go over these odd brackets in the next chapter, but suffice it to say that they designate sections of an ERB template that should be interpreted in Ruby, and in this case also appended to the template.

But why a class variable? Remember that all templates are included as methods of the abstract controller. Consequently, class methods from the controller instance are also available to the template itself.

3.7.2 Basic rendering

In order to render a template, we use the controller method render. Note that render isn’t some magical method that takes control of your action. Instead it simply evaluates a template returning a string. Thus, it must be the final evaluation step on your controller action to have any effect. In the following modification of our first example, the rendered template is mistakenly not the final step of the action, and 'bye' ends up being the response instead:

image

The render method can take various parameters. The simplest of these is a string. When you render a string, the render method embeds the string within the layout (more on this later) or, if no layout is available, simply returns the string itself. Here is an example:

image

3.7.3 Template

The render method may alternatively take a symbol as one of its parameters. This switches the template to be rendered from the action name to a stringified version of the symbol. This is most commonly used to render a form when form submission has failed. We’ll see an example of this in Chapter 6 on helpers, but for now, here’s a simpler example based upon the first. Note how the template’s name has been changed.

image

Another way of specifying the template is to pass in an optional hash with :template with the template’s name as its value:

image

3.7.4 Formats

We can also specify the format with which an action will be rendered. By default this format is HTML, but we can override this by using the hash key :format. Be aware that this requires that a template with that filename exists.

image

We can accomplish the same thing in two other ways. The first is setting the content_type, which may have been automatically set by the router from the value for the route parameter format:

image

The second is using the method render_json. Merb adds a render_ prefixed method for each of the MIME types to which it can respond. Here we use it in our action:

image

Occasionally there are several ways to do the same thing. Our recommendation is to stick with the simplest. Of course, deciding what that is, is a matter of opinion.

We can also specify the formats provided by a controller when we want to be explicit. These can then be automatically specified as the formats in request parameters. The two methods that open up this possibility are provides and does_not_provide. Both of these are available as class and instance methods. The example below demonstrates both methods.

image

3.7.5 Status

You can also set the status code used in the response through render by setting :status to some integer. This, however, doesn’t actually affect the render itself but instead only incidentally sets the value of status used later by the Merb server in crafting the headers for the response.

image

3.7.6 Layout

A layout is a parent template in which a rendered template can be embedded. Layouts typically reside in app/views/layouts/. The default layout in a controller without a specified layout is app/views/layout/:controller.html.*, where :controller is the controller’s name in snake case. If that is not found, the controller looks for app/views/layouts/application.html.*. Either way, this also requires that we indicate where the render content should be placed. To do this we must use the method catch_content :for_layout. Below we put all of this together to produce the output "START hi friend FINISH":

image

We can specify an alternative layout in various ways. We can do this controller-wide using the layout method. Alternatively, we can set it as the value of the :layout key in the render hash. Note that if we use the value nil, no layout will be used and the template will be rendered alone:

image

3.7.7 display

An alternative way to render a template is to use the method display. In scenarios where there is an object that essentially forms the entirety of the response, this method may be a better fit than render, as it falls back on serialization of that object when an appropriate template isn’t found. We’ll use this effectively to handle multiple MIME templates, including XML and JSON, in Chapter 6. For now, the following contrived example shows the gist of the intent:

image

3.7.8 render_chunked

Occasionally we may want to send data chunked to save on memory usage. This would make sense especially if we were going to send over a large log file that we were reading from a private location. In this example taken from the API, we pass the method render_chunked a block that contains looped calls to send_chunk:

image

3.7.9 render_deferred

If we are using the Mongrel web server, then another method available to us is render_deferred. When we use it in place of render, we can pass in a block that is executed before the final rendering. Nonetheless, the Merb thread is not locked during its evaluation of the block and is capable of handling other requests.

image

3.7.10 render_then_call

Another method available to us is render_then_call. This method renders normally, but the block it is given is called after the response is sent. Thus, this block is evaluated outside the request-to-response cycle, making it a great place to put response-independent, time-intensive instructions:

image

We hope that sleeping on the job isn’t actually part of your application’s specifications.

3.8 run_later

A better way of calling a block later on is to use the web-server-agnostic run_later method. This method places the block into the worker queue and has it run at some point after the response is handled. We can use this extensively once again for time-intensive instructions that are not necessary for the controller response. Also, because run_later is essentially just a means of pushing blocks into a queue, we can have as many of them as we like.

image

3.9 Sending and streaming

Sending and streaming allow us to programmatically deliver data from inside controller actions. This may seem odd at first when you could simply serve a static resource, but there are scenarios when you’ll find this helpful. For sending, this may be when you want to protect a file behind filters that among other things authorizes users. In the case of streaming, it may be because files are large and serving them a chunk at a time saves memory.

3.9.1 Sending files

The method for sending a file is simply send_file. It requires only a single parameter, the path to the file, but you can explicitly set the filename, disposition, and file type through an options hash. Below we send a file only if the request comes from an authenticated user.

image

3.9.2 Streaming files

Streaming is the process of sending information to the client in chunks, which saves on memory when we’re dealing with large files. The Merb method stream_file offers this benefit. In the example below, we stream data from Amazon S3 containing a user’s video intro stream_file.

image

3.10 Conclusion

Controllers are an essential part of any Merb application. In this chapter we exhibited their central importance by almost exclusively coding all the examples using only controllers. Our tour of features such as filters, exceptions, and rendering should already enable many application developers to get a head start on building Merb applications. As we move on to the next chapter on views, remember that controllers and views are internally tightly coupled within the framework; the next chapter is more a discussion of Merb’s interaction with templating engines than anything else.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.142.199.181