Chapter 6. Helpers

Helpers are methods that are widely available throughout your application. They are primarily used within templates but are also available within controllers, given the tight coupling of controllers and views in Merb.

The use of helpers greatly simplifies the most common tasks application developers face. Consequently, their structure exhibits some of the best refactoring that web application developers typically run into. That said, we’re going through the helper source extensively, so that you will be comfortable with the methods you use all the time but also with designing your own.

Before continuing, it is worthwhile to mention that most active helpers exist in the module Merb::GlobalHelpers, which is included at boot within all controllers. You can add your own helper methods to this module within the file app/helpers/global_helpers.rb. Alternatively, particular controllers may have their own helpers. These should be placed in the file app/helpers/#controller_name_helpers.rb. The rest of this chapter goes through the helpers found within the module merb-helpers.

6.1 Truncate helper

One of the most commonly used helpers included in the Merb helpers is truncate. It truncates a string at a point and then appends a suffix, making it perfect for the display of preview allotments of text on views:

image

The default suffix is '...', but by passing in a second parameter we can override this. Here’s the source to the method. Note that this helper is essentially a core class extension, which very rarely happens within helpers.

image

6.2 Numeric helpers

The numeric helpers have been included with the Merb helpers to add in some of the most common conversions applications make between numbers and strings. All of these helpers exist as utility methods of the module Numeric::Transformer and are made accessible through same-name instance methods in the Numeric class itself. Keep this in mind as we display the source to each of them.

6.2.1 Two digits

The two_digits helper does exactly what it says it does: adds a single leading zero to numbers under 10. This can be useful for displaying dates and is used in other helpers for just that:

8.two_digits # => "08"

The source behind two_digits is divided into two methods, one API private and the other public:

image

6.2.2 Minutes to hours

The helper minutes_to_hours builds on the two_digits helper, allowing us to conveniently convert minutes to hours:

345.minutes_to_hours # => "05:55"

Here’s the utility method where everything interesting happens:

image

6.2.3 Currency strings

The helper method to_currency converts a numeric into a standard currency string like "$1.99". We accomplish this with the following:

1.99.to_currency # => "$1.99"

We can also use other currencies by specifying a locale. This automatically modifies the unit, format, precision, delimiter, and separator:

20.to_currency(:uk) # => "£20.00"

The predefined formats are US, UK, AU, FR, and RU. However, you can easily add more formats using the method add_format:

image

Note that in the last two lines we also changed the default currency.

There are also two methods used by to_currency that are available to the application developer. Let’s take a look at their source, once again noting that a public instance method in Numeric makes them accessible:

image

From this we can easily determine how to pass in options for delimiter, separator, and precision that override the defaults. Though the methods above are pretty standard fare for Rubyists writing helpers, you may be interested in studying them if you haven’t done extensive string formatting before.

6.3 Date and time helpers

The module DateAndTimeFormatting mixes a number of helper methods into the DateTime, Date, and Time classes. It also stores a number of predefined formats and gives you the opportunity to add your own.

6.3.1 Formats

Let’s first take a look at the list of provided formats. These can be accessed as a hash by invoking the class method formats on any of the data and time classes.

db—formats a time as databases typically store it

time—outputs just the time in 24-hour format

date—outputs just the date as year, month, and day

short—displays only the day, month (abbreviated), and time

long—displays the full date, written out

rfc822—formats the time to match RFC 822

We can use these directly by passing one in as the parameter of the method formatted on an instance of any date or time class:

Time.now.formatted(:date) # => "2009-02-14"

Adding new formats for your application to use is simply a matter of using the add_format method on any date or time class:

image

Note that when you add a format, it is added not only to the class on which you used add_format but to all date and time classes. Let’s peek at the source for this method to understand how this is done:

image

image

The formats are all stored within a module called DateAndTimeFormatting. This module is included within both Date and Time, and whenever either is used to add a format, it affects the module itself. It is noteworthy that this helper is consequently not thread-safe. This is because when you add a format in one thread it does not affect the other. To overcome this, we recommend that you put a mutex around any dynamically created formats, or simply define new formats in a boot loader before the application loads.

6.3.2 Ordinals

The module Ordinalize is used extensively by the date and time helpers and therefore is included there. Nonetheless, it is essentially an extension of the Integer class. You can use it directly on any integer by calling the method ordinalize:

image

The method for ordinalize is expectedly simple, using only modular arithmetic and one if statement to create the result:

image

6.3.3 Time DSL

The Merb helpers also include a Time DSL similar to the one found with Rails. This allows us to go from numeric to number of seconds using methods that mimic natural language. For example:

image

There are also a couple of DSL methods that generate time objects:

image

Rather then present a comprehensive list of the methods, we present the extremely simple source code to these methods, including their aliasing:

image

image

6.3.4 Relative time

To make the output of dates more relevant to the moment, relative time can be used. For example, instead of giving yesterday’s day, we simply say “yesterday.” There are Merb helpers that can help translate date and time objects to relative time strings. These utility methods are relative_date, relative_date_span, relative_time_span, time_lost_in_words, and prettier_time. Here we use them within a view:

image

As you may have guessed, these methods are included within the module Merb::GlobalHelpers and are available within views. This also makes them a great template for structuring your own reusable global helpers. Here we present the source to the prettier_time method but demonstrate the organization of the helpers:

image

6.4 Cycle helper

The cycle helper may at first seem to be a peculiarity among helpers, but it can be put to extensive use. Inside the module Merb::helpers::Text, it is, like the relative time helpers, included within the GlobalHelpers and thus available to all views. It can be used to continuously step through a list of values, outputting them as necessary. Here we put this to use to alternate the class names on rows of a table:

image

Cycles can also be reset, so if we had one table followed by another, we might reset the cycle before outputting the second table:

image

Alternatively, in order to make the positions of cycles independent from one another, we can name each of the cycles we use by passing in a hash as the final parameter. This could be important among cycles that reset within cycles.

image

Here’s the source behind the cycle method:

image

Note that the default cycle name is :default and that it is extracted from the values using the method extract_options_from_args!, which is an extension the Merb core makes to Kernel:

image

6.5 Tag helpers

The tag helpers, of which there are only four, are fundamental to the creation of HTML and XML entities. Let’s go through the code that pulls these together:

image

We find that the tag helpers, like other helpers, are contained within a module and then included within the module Merb::GlobalHelpers. Remember that this module is included within the Merb::Controller, and consequently these methods are available to all controllers and all views. The first method, tag, can take three arguments: name, contents, and attrs. Thus we can create HTML entities as follows:

tag("div","Hello There", :class => "message")

It also takes an optional block that we can use to place in nested entities:

image

Most of the hard work is done through the other helper methods and to_html_attributes. Chances are you will not use these helpers within templates themselves, because their real target is within other helpers, allowing for the construction of HTML entities in an abstract, template-agnostic way. In the next section, we’ll see just that.

6.6 Form helpers

The design of the form helpers is more complex than that of any of the other helpers described in this chapter. With that in mind, we will not cover the API of helpers entirely in this section and aim only to fundamentally understand the design of helpers by picking apart its quintessential parts. Let’s start off with the underlying builder class upon which the actual helpers rely.

6.6.1 Builders

The Form::Builder module holds

image

Note the class Base. It has access to the tag helpers previously described, so we can expect them to be littered throughout the rest of the code. It’s also the class that will be used under the hood by the form helpers themselves. As such, it must maintain three instance variables, two of which may simply end up being nil. The first of these, obj, is meant as a reference to the model object with which the form may be associated and may be nil. The second, name, holds the name of the form context, which again is related to the model object and most of the time derived from it. This parameter can also be nil without causing issues. Finally, the parameter origin links us back to the actual form helper making use of the base. This parameter is strictly necessary.

image

The two methods form and fieldset are used indirectly in the production of form and fieldset elements. We have grouped them together for you because they both make use of blocks passed to them. It’s worthwhile to point out that the capture method is employed in handling these blocks, which ultimately means that they will be handled by the template engine. You may also have spotted the use of process_form_attrs:

image

The processing of form attributes does three things. First, it checks to see if we’ve set the form to use the GET method. If so, it leaves it alone. Otherwise it will use POST. In general, all forms should use POST, unless the form is meant simply as an interface to some complex set of data. The best example of this would be a search form leading to a filtered index. Second, irrespective of the actual method used on the form, the method figures out what the best REST verb is. This later comes into play as a hidden form element that, as we saw very early on while studying the Merb fundamentals, overrides the actual request method used from the perspective of the router. This again is meant to compensate for the lack of availability of all HTTP methods among browsers. Third, the method allows us to use :multipart => true as shorthand for specifying that the form should accept uploads.

image

Note that the methods for several fields are dynamically generated. This is because there is inherently nothing special about them. The biggest difference between bound and unbound variants is that the bound variants automatically set a name and value based upon the object of the form context before invoking the unbound method. Below we see the private methods used to generate the name and value attributes.

image

You may also wonder what the method update_*_controls is for, but before we get to that let’s analyze at least one of the more complicated form element fields:

image

The checkbox control is more complicated than those we have seen before, or at least the unbound variant is. Notice how the method bound_check_box doesn’t set a field value. Where is this work being done?

image

Inside the cascaded call to update_bound_check_box we find that the checked attribute is set to true or false based upon either the matching of the control value with the on value or otherwise when some value generically considered true has been used. Ignoring the specifics for a moment, the method update_bound_check_box exemplifies the extension of form field behavior. This technique is used not only with many of the bound controls but also with many of the unbound ones.

image

Remembering how the bound checkbox eventually defers to the behavior of the unbound checkbox, we see that the code above is used by both methods. The argument errors are ways of making sure developers don’t misuse the helper, while the final line shows us that despite whatever value it may have had in the past, the checked attribute simplifies to the HTML oddity of either being present and equal to "checked" or not there at all. We’ve left out the numerous other methods used behind the scenes by form fields, but we recommend the pure API for help with the specifics of these helpers. If, however, you do run into a bug, you’ll know right where to track it down.

The Base class for form builders can be extended. For instance, the following subclass of Base adds labels to forms and is used by the Merb form helpers by default:

image

The method label is used to build a label element, but we don’t typically call this method ourselves:

image

Instead, the methods for individual form elements have been extended to include labels automatically. The code above displays only some of these extended methods. However, all of them make use of the method unbound_label to determine what to name and caption the label:

image

Altogether, the application developer should be aware that form helper methods that have not been handed a value for the :label key within the attributes parameter are not preceded by a label.

Two other extensions of the form builder come as modules. Take your time understanding both, as they probably serve as the best structure for extending the form helpers for your own applications.

image

This module defines a method error_messages_for, which can be used to output validation errors related to form objects. Many of the lines are there to handle the various ways ORMs store this error within the properties of an invalidated object.

image

The private method update_bound_controls does something sweet with ease: It adds a CSS error class on all specifically invalidated element fields. By now, update_bound_controls should no longer seem pointless but instead quite useful to developers needing to extend the base form builder.

image

Above we see the inclusion of the module within a subclass of the Form builder class. Note, however, that Merb does not use the FormWithErrors builder by default, but it does use the module above through the builder we’re about to see.

image

The extension of the method process_form_attrs allows us to automatically set the action of a form when it is bound to a resource object. In practice this means a form bound to a RESTfully controlled model.

image

Ending our discussion of form builders, we arrive at the form builder used by default with Merb, ResourcefulFormWithErrors. Having gone through the greater part of the source for the Merb form builder, you should be aware of how form elements are handled under the hood. However, we did skip the specifics for a number of elements, so you may need to consult the Merb documentation at times, or otherwise adventurously dive into the source code, which by now should cause you no fear.

6.6.2 Helpers

The Helpers::Form module holds the actual methods that application developers use with regard to forms. With that in mind, though we will be going through the raw source for them, it’s worth taking the time to let these methods sink in for later use.

image

The concept of form context is critical to the form helper methods. This is because forms can associate with model objects, and the context of those objects affects how particular form elements should semantically be created. The two methods form_contexts and current_form_context serve as a foundation for determining the current context:

image

The application developer should pay particular attention to the method form. It is used for forms without any model object context. As a consequence, we see it pull up what is internally called the singleton form context. This context initiates a new form builder or retrieves the last one built. The form method then delegates the handling of its parameter block to the same-named builder method as in the last section. This, however, is not the only way to construct a form.

image

In contrast with the method above, form_for takes a name in addition to its attributes. This name is used to form a specific form context. Note that this name can be either a string/symbol or a variable. This means that :user and @user are equivalent. We recommend that you stay away from using strings or symbols because they apply only to instance variables and consequently are not applicable to the local variables of partials. Another takeaway message from the code above is that the form block is handled through a yield statement that is surrounded by the push and later pop of the form context array. As a web application developer, you may be wondering, Why all the complexity? After all, forms cannot be embedded within one another. Our helpers, however, allow for something a bit different:

image

The three helpers fields_for, fieldset, and fieldset_for offer us a way of changing the form context from within another form. This versatility means that we can easily produce the appropriate form elements for multiple objects within one form. The distinction between fields_for and the other two is that fields_for does not create a fieldset HTML entity. Of course, of interest to us now is the helper method for the particular form elements:

image

You may find it odd that none of the methods above has any body. The reason for this is to make them available even before they are dynamically generated below.

image

The templated method above holds the actual code for each of these methods. If it’s your first time, note the explicit use of _ _FILE_ _ and _ _LINE_ _ with a class_eval. These are there so that exception output actually directs us to the relevant file and line. Inside the method template itself, it delegates to either the bound or the unbound builder methods. The way of determining which is simple:

image

We realize that the only thing that matters is whether the helper method’s first argument is a symbol or not. This is because the methods above accept a hash of arguments, but a symbol can be added before this hash, effectively indicating that it should be bound within the current form context. The symbol given, therefore, should be that of a model accessor. As we previously saw, this is used to dynamically generate the name attribute on the element. If the form element we need should not be bound, however, then we can explicitly give it its name by setting the value of :name within the attributes hash.

image

The label, button, and submit helper methods of course do not need to be bound, so they have been handled separately.

image

The method error_messages_for can simplify the output of model object validation errors. Note that we can pass in alternatives to its defaults, which is certainly useful if we need to deviate from standard text.

image

Finally, the delete_button method creates a delete form consisting of only a hidden element and a delete button. This helper needs either a specific object to delete or a URL pointing to the path requesting its deletion. The reason for this is simply to avoid misuse of GET requests to alter persisted states on the server.

6.7 Conclusion

In this chapter, we explored in depth the code build helpers. That said, both application developers and framework enthusiasts should be able to take away direct insight into how to extend the controllers and views of Merb applications with just about any kind of helper method. We also saw, principally through the form helpers, how a model object can more easily be used within views, tucking away applicable logic almost exclusively into helper code.

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

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