Quantcast

Delving Deeper into the Active Record with Ruby-on-Rails

(No Ratings Yet)
Loading ... Loading ...

If you're new here, you may want to subscribe to my RSS feed. So that you can read the latest updates about Web2.0 tools, Making Money Online, Tips in SEO, Ajax and many more. Thanks for visiting ProgramimiCOM!

In addition to allowing on-the-fly schema mapping, the Active Record provides a variety of services helpful to complicated table situations. Keep reading to learn more.In the previous part of this

series, I introduced the concept of Active Record. Going by the philosophy of “Convention-over-Configuration,” Active Record eliminated the need for configuration files and brought forward on-the-fly schema mapping. In other words, with the least lines of code, one could map tables to the corresponding classes without worrying about re-mapping the tables and classes when the schema changed.

However, all this was discussed from the perspective of a single participating table. The real world is totally different; there may be hundreds of participating tables with half of them having various relationships between them.

In this discussion I will be focusing on those services provided by Active Record that facilitate advanced concepts. These include participating relationships, composition mechanisms, and so forth.

In the next two sections of this article, I will be discussing the advanced services provided by Active Record. In the final section, I will be putting the concepts introduced in the earlier two sections into practice. That’s the outline for this discussion.

Active Record: Into the Deep

Active Record’s specialty lies in providing services for advance mapping and data validation techniques without the usually inherent language complexity. Without much ado let’s look at these services. There are two services that solely focus on mapping. They are Relationship Mapping and Act As Mapping. They can be thought of as basic and advanced mapping. Relationship Mapping provides basic database-based relationship mapping, whereas Act As Mapping provides fine grained and advanced mapping based on the basic functionality of Relationship Mapping. Here are the details.

Relationship Mapping

In real world applications, tables never exist in isolation. They are related at the database level using relationships based on the foreign key concept. One table can be related to another table through one-to-one, one-to-many or many-to-one relationships. Active Record bases its object-to-object relationship on how the corresponding tables are related at the database level. On the basis of types of database level relationships, there are three types of basic mapping in Active Record:

  • One-to-one Mapping
  • One-to-many Mapping
  • Many-to-many Mapping

Each of these are mapped using two-way mapping. That means the classes on both sides of relationships know how they are related to the other class.

In one-to-one mapping, a foreign key in one row of a table references at most a single row of another table. For example, let’s take two tables - INVOICES and ORDERS. The following diagram shows the relation between the tables:

r-o-r_v_1.JPG

To map tables with a one-to-one relationship, Active Record provides two declarations that have to be added to the corresponding classes. They are  belongs_to and has_one. The belongs_to declaration appears in the class/model for the table that contains the foreign key, whereas has_one is declared in the class which is on the other end i.e. the one whose primary key is acting as the foreign key. To map the classes according to the relationship between INVOICES and ORDERS, the addition to the classes would be:

class Order < ActiveRecord::Base

has_one :invoice

. . .

class Invoice < ActiveRecord::Base

belongs_to :order

Since for each Order there is at most one Invoice, the Order class contains the has_one declaration connecting it to the object of the Invoice class. Similarly, the Invoice class contains the belongs_to declaration to map it with the Order class, more specifically the object of Order class.

In a One-to-many relationship, a primary key in one row of a table references or is associated with an arbitrary number of rows in another table. For example, the relationship between ORDERS and LINE_ITEMS is that of one-to-many. The DDL of the tables will make it more clear:

DDL for ORDERS

create table orders (

id int not null auto_increment,

name varchar(100) not null,

/* … */

primary key (id)

);

DDL for LINE_ITEMS

create table line_items (

id int not null auto_increment,

order_id int not null,

quantity int not null default 0,

unit_price float(10,2) not null,

constraint fk_items_order foreign key (order_id) references orders(id),

primary key (id)

);

An order can be associated with any number of line-items. To map such a relationship, one must use the declarations has_many and belongs_to. The declaration has_many must be declared in the class representing the table at the “one” end of a one-to-many relationship, whereas belongs_to is declared in the class representing the table at the “many” end of the relationship. To illustrate further, below are the classes corresponding to the ORDERS and LINE_ITEMS tables with the mapping declaration embedded:

class Order < ActiveRecord::Base

has_many :line_items

. . .

class LineItem < ActiveRecord::Base

belongs_to :order

Using the has_many declaration, the Order class is associated with the line_items class and tells the framework that one instance/object of the Order class is associated with many instances of the Line_Items class. The belongs_to declaration works in the same way as it works in one-to-one relationship mapping.

When many records of one table are associated with many records of another table, then the tables have a many-to-many relationship. To implement such a relationship, a link/join table needs to be used. The join table contains a foreign key for each of the tables its linking, so each row in the join table represents a linkage between the two tables. For example, PRODUCT and CATEGORIES have a many-to-many relationship. To implement the relationship, a link table has to be introduced: CATEGORIES_PRODUCT. It contains foreign key references to both tables. Here are the DDL of all three tables:

DDL for PRODUCTS

create table products (

id int not null auto_increment,

title varchar(100) not null,

/* . . . */

primary key (id)

);

 

DDL for CATEGORIES

create table categories (

id int not null auto_increment,

name varchar(100) not null,

/* … */

primary key (id)

);

DDL for CATEGORIES_PRODUCTS

create table categories_products (

product_id int not null,

category_id int not null,

constraint fk_cp_product foreign key (product_id) references products(id),

constraint fk_cp_category foreign key (category_id) references categories(id)

);

The conventional way of mapping a many-to-many relationship would contain a declaration for the join/link table too. But that is not done with Active Record. Only the main tables are required to be mapped. It assumes that the join table is named after the two tables it joins (with the names in alphabetical order). To map the main tables, the classes corresponding to them must have the following declaration: has_and_belongs_to_many. This declaration links them both through the join/link table which is taken care by the Active Record.

class Product < ActiveRecord::Base

has_and_belongs_to_many :categories

. . .

class Category < ActiveRecord::Base

has_and_belongs_to_many :products

In the above example there is a mention of the link/join table. The reason is that once Active Record sees the declaration has_and_belongs_to_many in both  tables, it checks for the link table categories_products automatically. Thus “Convention-over-Configuration” works here too.

Acts As Mapping

The Relationship Mapping previously discussed provides mapping that is in one-to-one correspondence with the underlying database. In most cases, such a mapping is all that is required. However, this is simple in terms of variation in data structures. There are situations where data may be required to be presented in a different way. This is where Acts As Mapping plays a key role.

Acts As Mapping is built on top of a has_  relationship. Active Record provides two types of  Acts As Mapping: Acts As List and Acts As Tree. As the name suggests the former provides List data structure and the later provides Tree data structure.

Acts As List

In a has_ relationship, if acts_as_list is declared in a class representing a child (the many end of the one-to-many relationship), the class representing the parent can view the child like a list. In other words, it gives the child list-like behavior. It facilitates the parent to traverse the children around in a list as well as remove the children from the list.

To implement such a behavior, the child table needs a column called position. Here again convention takes precedence. If the column is named position, Active Record will automatically use it. Active Record uses this column to record the position of the child. An example will make the concept more clear. For brevity I will be using tables named PARENTS and CHILDREN. Here are the DDL:

create table parents (

id int not null auto_increment,

primary key (id)

);

create table children (

id int not null auto_increment,

parent_id int not null,

name varchar(20),

position int,

constraint fk_parent foreign key (parent_id) references parents(id),

primary key (id)

);

The following are the corresponding classes:

class Parent < ActiveRecord::Base

has_many :children, :order => :position

end

 

class Child < ActiveRecord::Base

belongs_to :parent

acts_as_list :scope => :parent_id

end

               

The Parent class has one extra argument to the has_many declaration:  :order. It ensures that the array is fetched from the database in the correct order. In the Child class, acts_as_list is declared and the scope is that of the parent_id or  in other words, ensures that the children are placed in the corresponding parent’s list instead of a global list. Now let’s set up some test data - three children named One, Two and Three for a parent as follows:

 

parent = Parent.new

%w{ One Two Three}.each do |name|

parent.children.create(:name => name)

end

parent.save

The following statements show how the children display behavior akin to that of a list:

#A simple method to let us examine the contents of the list.

 

def display_children(parent)

puts parent.children.map {|child| child.name }.join(“, “)

end

 

display_children(parent) #=> One, Two, Three, Four

puts parent.children[0].first? #=> true

 

two = parent.children[1]

puts two.lower_item.name #=> Three

puts two.higher_item.name #=> One

 

parent.children[0].move_lower

parent.reload

display_children(parent) #=> Two, One, Three, Four

parent.children[2].move_to_top

parent.reload

display_children(parent) #=>

The various move operations update the position. The parent must know this change immediately, hence the reload operation is called after the move_lower or move_higher operation.

Acts As Tree

The other kind of data structure that is commonly used is Tree. There are scenarios where the rows of a table need to be represented in the form of a tree structure. For this Active Record provides the Acts As Tree mapping. To use this, the corresponding table needs to have one additional column — parent_id  — which is a foreign key reference back into the same table, linking child rows to their parent row. The pictorial representation would be as follows:

r-o-r_v_2.jpg

The best example of such a scenario is the previously discussed CATEGORIES table. Each category may have a sub-category and each sub-category may have its own sub-category. To make matters simple, let’s create a CATEGORIES table having id, name and parent_id. So here is the DDL:

 

create table categories (

id int not null auto_increment,

name varchar(100) not null,

parent_id int,

constraint fk_category foreign key (parent_id) references categories(id),

primary key (id)

);

Next, in the corresponding class, the declaration acts_as_tree has to be declared.

class Category < ActiveRecord::Base

acts_as_tree :order => “name”

end

The parameter :order tells the framework that the children of a particular node must be displayed according to the value of the name column. The following statements set up the test data as one would populate a tree:

root = Category.create(:name => “Books”)

fiction = root.children.create(:name => “Fiction”)

non_fiction = root.children.create(:name => “Non Fiction”)

non_fiction.children.create(:name => “Computers”)

non_fiction.children.create(:name => “Science”)

non_fiction.children.create(:name => “Art History”)

fiction.children.create(:name => “Mystery”)

fiction.children.create(:name => “Romance”)

fiction.children.create(:name => “Science Fiction”)

Now let’s see how to access the data:

display_children(root) # Fiction, Non Fiction

sub_category = root.children.first

puts sub_category.children.size #=> 3

display_children(sub_category) #=> Mystery, Romance, Science Fiction

non_fiction = root.children.find(:first, :conditions => “name = Non Fiction)

display_children(non_fiction) #=> Art History, Computers, Science

puts non_fiction.parent.name #=> Books

Here I have used the display function created previously. So creating a tree structure using application code cannot get any simpler than this.

That brings us to the end of this section. In the next section I will develop an application that utilizes the types of mapping just discussed.

Mapping and Rails in the Real World

Now let’s look how the mapping discussed fits into the whole Rails framework. I will be extending the existing application developed in the previous part by adding a new table and corresponding operations. I will provide a custom view part to show the use of the tree data structure. So let’s get started. First comes the table. It’s the CATEGORIES table, and here is the DDL for it:

create table categories (

id int not null auto_increment,

name varchar(100) not null,

/* … */

parent_id int,

constraint fk_category foreign key (parent_id) references categories(id),

primary key (id)

);

Next comes the model corresponding to the table. The command to generate the model class is:

ruby script/generate model User

In the generated class I am giving the declaration acts_as_tree to tell the framework that I need the tree data structure.

class Category < ActiveRecord::Base

acts_as_tree :order => “name”

   end

As you can see, I am reusing the table and model discussed in the previous section.

Next comes the controller. The command to create the controller is:

 

ruby scriptgenerate controller Mapping

 

class MappingController < ApplicationController

 

scaffold:category

 

def list

end

end

 

Every other operation will be provided with a default scaffold except for listing/view. Next comes the definition of listing. Since the application is for a tree structure, the operation for creating the tree will be done in the list method.

class MappingController < ApplicationController

scaffold:category

def list

@root = Category.create(:name => “Books”)

fiction = root.children.create(:name => “Fiction”)

non_fiction = root.children.create(:name => “Non Fiction”)

non_fiction.children.create(:name => “Computers”)

non_fiction.children.create(:name => “Science”)

non_fiction.children.create(:name => “Art History”)

fiction.children.create(:name => “Mystery”)

fiction.children.create(:name => “Romance”)

fiction.children.create(:name => “Science Fiction”)

end

end

 

Next is the list.rhtml. Here is the code for list.rhtml.

<ul>

   <li>

        <%=@root.name%>

           <ul>

                <li>

                    <% subcat=@root. root.children.first%>

                     <%=subcat.name%>

                  <!-same for all others 

               </li>

            </ul>

   </li>

</ul>

 

That brings us to the end of this part. However, the services provided by Active Record are many. The most important are data validation, transactions and single table inheritance. These will be topics of discussion in the future. Till then…

by  A.P.Rajshekhar 

Ruby-on-Rails: Understanding the Basics of Active Record

(No Ratings Yet)
Loading ... Loading ...

Ruby on Rails handles data manipulation with the Active Record, which provides an Object Relational Mapping framework. If these sound a little like foreign words to you, keep reading; you’ll find that the way RoR handles ORM is a little different, and perhaps easier, than you might see it handled with other languages.Data and its manipulation is central to any application, whether it is a desktop or web-based application. Data can be represented and manipulated using different techniques.

One of them is the Object Relational Mapping technique or simply ORM. ORM maps the relational tables to the object-oriented classes. ORM frameworks provide the mapping and corresponding object/data manipulation services. In most of the server-side technologies, ORM frameworks constitute a totally different component stack. Hence it becomes the developer’s job to do the groundwork to create a connection between the ORM framework and other frameworks (such as web frameworks).

In the context of ORM frameworks, RoR is an exception. The ORM framework is built into the core of RoR in the form of Active Record. In this discussion, the focus will be on the basics of Active Record. The first section will focus on the basics of Active Record. The second section will detail the steps required in connecting the database, and in the third section I will use Active Record along with ActionController and ActionView in an example. So that’s the agenda.

Active Record: What is it?

Active Record is an ORM framework or layer distributed along with RoR. Even though the term distributed is used, the Active Record is built into the core of RoR. Since Active Record is an ORM layer, it provides the following mapping services:

1. Tables to Classes

2. Columns to Attributes

3. Primary Keys to Ids

4. Rows to Objects

The major difference between Active Record and other ORM frameworks/layers is the way mapping is done. Most of the popular ORM frameworks such as Hibernate use XML as the mapping container. However Active Record uses a convention-over-configuration methodology. Let me show you how it is done.

Tables to Classes

To map a table to a class, the class has to be derived from ActiveRecord::Base i.e. the Base class present within the ActiveRecord package. What essentially happens when a class is derived from ActiveRecord::Base is that the derived class acts as a wrapper for the database table. In understanding the table’s name, Active Record assumes that the pluralized name of the class is the name of the table. If the class name has multiple capital letters, it is assumed that the table name contains underscores between the words. Some of the examples are:

Table Name         Class Name

Orders                   Order

Line_Items          LineItem

Data                      Datum

This behavior can be turned off by the following two steps:

  • Set the global flag ActiveRecord::Base.pluralize_table_names to false. This flag is present in the environment.rb file in the config directory.
  • Override the default generation of a table name using the set_table_name directive.

For example, if a table named Orders is to be mapped to the class Order the code would be:

 class Order < ActiveRecord::Base

end

But if the class Order needs to be mapped to a table Order_QA then the code would be:

 class Order <ActiveRecord::Base

set_table_name “Order_QA” # Not “Orders”

end

Now let’s see how columns are mapped to attributes.

Columns to Attributes

Once a table has been mapped to a class, there is no requirement to explicitly map the columns to the attributes. That’s because Active Record determines the attributes of a table dynamically at runtime. Typically, Active Record reflects on the schema to configure the class that wraps the table. The following shows how the SQL data types are mapped to Ruby’s data types:

image001r.jpg

Next let’s look at how Primary key is mapped.

Primary Key to Ids

If you remember the example application from the first part of this

series, the table’s Primary key was named id and had the data type of integer. Though the logical one would have been the Order_id, yet this id was used. At first glance, this might be considered preposterous. However, if one looks at the long run, the id as the Primary Key has its benefits.

Let’s say that the Order_Id is based on a 16 digit format including the Item id, user id, and so forth. In the future if the Order_Id has to be increased to 20 digits by including the last 4 digits of an RFID based code, all the dependent table’s columns would have to be changed. That’s a large order for even a medium-sized application. The mapping is done dynamically. However, if the requirement is to map an existing Primary Key then it can be done as follows:

 class Order <ActiveRecord::Base

set_primary_key “orderId”

end

Rows to Objects

Whenever a retrieve operation is performed on a class, the corresponding SQL query is fired at the database and the row is retrieved, which is then used to populate the object of the same class. The values of the column in the retrieved row become the values of attributes of the object. In a nutshell, the row is mapped into the object. For example, the following returns an Order object having the id of 27:

an_order = Order.find(27)

That covers mapping. Now let’s see the steps involved in performing CRUD operations using Active Records.

Active Record: Steps to using it

Active Record minimizes the configuration requirements, yet demands that certain conventions be followed. These conventions form part of the steps of working with Active Record. Following are the steps:

1. Creating the table(s)

2. Connecting to the database

3. Creating the ORM

4. Applying CRUD operation

Of these first step is purely convention based. The table has to follow the convention or else one would have to override the default values. Here are the details:

Creating the table(s)

Since convention takes precedence over configuration in RoR, the table has to be created following certain conventions unless you want to override the convention. They are:

  • The name of the table should be in its plural form.
  • The Primary Key should be name id with the data type as integer.
  • If the table references another table, then the Foreign Key should be of the form <referenced table name in singular>_id.

So applying the first two conventions an order tables, SQL script for MySQL would look like:



 create table orders (

id int not null auto_increment,

name varchar(100) not null,

/* … */

primary key (id)

);

Connecting to the database

Just like everything else with RoR, a database connection is also abstracted out. That means an Active Record application makes generic calls, delegating the details to a set of database-specific adapters. To connect to a database, the establish_connection() method of Base class of ActiveRecord has to be called with connection parameters. These parameters differ for different databases. For example the following call creates a connection to a MySQL database called testrails on the server localhost using the given user name and password:



 order = Order.find(123)

order.name = “raj” order.save 

Delete

Active Record provides the delete method for deleting data. It supports both single row deletion as well as multiple row deletion. The following deletes the record having an id of 20:

 Order.delete(123)

And the following deletes the records with ids supplied as a list:



 Order.delete([2,3,4,5])

That completes the bird’s eye view of how to apply CRUD to an ORM using Active Record. The advanced services provided by Active Record for CRUD will be discussed in the future. In the next section I will be using the services of Active Record along with ActionController and ActionView to create a login module.

Rails in the Real World

Without much ado let’s get to work and see how to implement a login module. The requirements of the module are as below:

  • A form that allows the users to enter their user name and password.
  • A simple userid password verification implemented to check the credentials of the user.
  • Once they are logged in, we need to record the fact somehow for the rest of their session (or until they log out).

On the basis of the requirements, the following are the components required:

  • User.rb – Model for the user table.
  • login_controller.rb – The controller orchestrating the flow.
  • login.rhtml – View providing form for logging in.

Here is the user table:



 create table users (

id int not null auto_increment,

name varchar(100) not null,

password char(40) null,

primary key (id);

Next comes the model class. Since we are using the Active Record in RoR, there is no need to use the establish_connection method. Instead I will be using the database.yml file with the following information (since I am expanding upon the demo application created in the first part):



 development: adapter: mysql

database: demo_development

username:raj

       password:

       host: localhost

The command to generate the model class is:

ruby script/generate model User

The model class contains two methods- try_to_login which in turn calls login. Here is the code:



 class User < ActiveRecord::Base

def self.login(name, password)

find(:first, :conditions => 
[“name = ? and hashed_password =    ?”, name,password])

end

def try_to_login

User.login(self.name, self.password)

end

end

The login method contains the find method with criteria. The details of this will be covered in the next part. The logic is simple – the try_to_login method gets called by the controller. This method in turn passes the data to the login method. The requirement of layering is to provide implementation abstraction. The login method tries to retrieve the data corresponding to username and password (before anyone complains about lack of security please bear with me as this is not a full-fledged implementation).

Next comes the controller. For that here is command:

ruby script/generate controller Login

And here is the code that implements the login validation and session establishment.



 class LoginController < ApplicationController

def login

@user = User.new(params[:user])

logged_in_user = @user.try_to_login

if logged_in_user

session[:user_id] = logged_in_user.id 
#creating the session

#and putting user’s id in   #it

redirect_to(:action => “index”)

else

flash[:notice] = 


“Invalid user/password combination” end

end

end

And here is the view :

<% @page_title = “Add a User” -%>

<%= error_messages_for ‘user’ %>

<%= form_tag %>

<table>

<tr>

<td>User name:</td>

<td><%= text_field(“user”, “name”) %></td>

</tr>

<tr>

<td>Password:</td>

<td><%= password_field(“user”, “password”) %></td>

</tr>

<tr>

<td></td>

<td><input type=“submit” value=” ADD USER ” /></td>

</tr>

</table>

<%= end_form_tag %>

That completes the login application. If you compare it with similar applications in any other language, the result would tell you that the number of lines is really less in RoR-based code. In this discussion there are certain aspects of Active Record that I have left out. The left out pieces of the puzzle called Active Record will be covered in the next part. Till then…

by A.P.Rajshekhar

Introducing the Google Maps API

(No Ratings Yet)
Loading ... Loading ...

Maps are becoming ubiquitous in web applications. They are being used as an effective and non-intrusive way of gathering geo-specific data from the user or to present geo-specific information to the user — for example, for tracking reports of shipments. However even two years ago, embedding a map within an application was a specialized area that required a good understanding of Geographical Information Systems (GIS). This changed with the arrival of Google Maps and its corresponding set of APIs, known as the Google Maps API.

Now a developer with a good grasp of JavaScript can without much ado embed an interactive map in a web application using the Google Map API. The questions that arise next are what exactly is the Google Map API and what are the steps one needs to follow in using it. The answers to these questions is the focus of this discussion.

In the first two sections of this article I will deal with the whys and wherefores of the Google Maps API. In the third section I will detail the steps you need to take when using the Google Maps API. The last section will focus on a real world example based on the steps discussed in third section. That is the outline of the discussion.

What is the Google Maps API?

Google Maps provides not only the map, satellite image or a hybrid of both but also an extensive range of operations on the map such as zooming, panning, information pop-ups, overlays and so forth. Google Maps API provides an interface into these operation through JavaScript objects. The beauty of the setup is that the functions work in the same non-intrusive way as the original Google Maps without the developer needing to know the details of AJAX or how it is implemented in Google Maps. The developer only needs to know the classes and their methods to access the services of Google Maps. The functions exposed by the Google Maps API can be categorized as follows:

  1. Configuration
  2. Controls
  3. Map Types
  4. Map State
  5. Overlays
  6. Information Window
  7. Map Navigation
  8. Events

The access to most of the group of functions mentioned above is through the methods of the GMap2 class. The GMap2 class forms the basis of map creation, display and manipulation.

Configuration

All of the aspects of any map provided by Google Maps are configurable, whether it’s the enabling of dragging and information windows or continuous zooming. The methods of the GMap2 class sectioned under configuration enable configuration of the map. The following are the most often used methods for configuring maps:

  • enableDragging() enables the dragging of the map. Dragging is enabled by default.

  • disableDragging() disables the dragging of the map.

  • enableInfoWindow() enables the information window.

  • disableInfoWindow() disables the displaying of the information window.

Controls

The UI elements, using which the user controls the map and its functions, come under the controls category. There are two main methods related to controls. These are:

  • addControl(control, [position]) adds the specified control to the map at the place specified by the position parent. The position parameter is optional.

  • removeControl(control) removes the specified control from the map.

Both of the above functions take instances of the GControl class. There are five existing instances of the GControl class: GSmallMapControl, GLargeMapControl, GSmallZoomControl, GScaleControl and GMapTypeControl. These can be passed to the addControl() method to add controls to the map.

More Google Maps API Functions

Map Types

Google Maps provides three types of map: a simple map that provides an outline-based map, a satellite map that streams the satellite-imaged maps and a hybrid map which combines both of the aforementioned maps. The map types provided by Google Maps are controlled by the following methods:

  • setMapType(type) sets the type of map to be displayed.

  • removeMapType(type) removes a map type that has already been set.

The type parameter is specified using the constants provided by the GMapType class. It can be G_NORMAL_MAP, G_SATELLITE_MAP, or G_HYBRID_MAP corresponding to maps of the simple, satellite image-based or hybrid types.

Map State

The methods that provide information about the state of the map come under this heading. The information provided by map state methods include whether the map is loaded or not, the current focus point or center of the map, and more. The commonly used methods are:

  • isLoaded() tells whether or not the map is loaded onto the client browser.

  • getCenter() provides the latitude and longitude of the center of the current view port of the map.

Overlays

By definition “A map overlay refers to a point or polyline that is added on top of the Google Map.” In essence an overlay means a point or line that is placed on the map to distinguish it from the rest of the map. The most used methods in this category are:

  • addOverlay(overlay) adds an overlay presented by the overlay object passed as a parameter.

  • removeOverlay(overlay) removes an overlay already added and represented by the overlay object passed as a parameter.

The overlay object can be of the GPoint or GPolyline types.

Information Window

When an overlay is clicked, a window containing detailed information can be displayed. It is called the information window or info window in short. The following are the main methods used to control an info window:

  • openInfoWindow(latlng,dom,[opts]) opens an information window at the point specified by latlang and with the data specified as dom which is a DOM node.

  • showMapBlowup(latlng,[opts]) opens an info window at the specified latlng containing the close-up view of the latlng specified as a parameter.

The parameter latlng is of the GLatLng type.

Map Navigation

The navigation of the map can be controlled using the methods provided under this category. The commonly used methods are:

  • setCenter(center,[zoom],[type]) loads the map focused on the point specified by center with an optional level of zoom and type of map.

  • panTo(center) navigates to the point on the map specified by center.

  • setZoom(level) zooms into or magnifies the current center to the level specified with the parameter level.

Events

The Google Maps API provides methods to intercept any event taking placing on the map. The common events supported by the Google Maps API are:

  • click is generated when the user clicks on any point within the boundaries of the map.

  • move is fired when the map is moving or panning. During panning it may be fired many times.

  • moveend is fired when the panning is completed.

That brings us to the end of the first part of our discussion. In the next section I will detail the steps required to work with the Google Maps API.

Using the Google Maps API, Step By Step

Now that the services provided by the Google Maps API have been discussed, let’s see what steps we need to take to use the API. To use the Google Maps API, two main steps have to be followed:  acquiring the registration key and setting up the map. The second step consists of sub-steps that actually deal with the setting up of HTML and the Google Maps API library.

Acquiring the Registration Key

It is through the registration key that one can access the API. A key can be used within a web directory i.e. the files within that directory and its subdirectories can make use of the key. To get the key, go to the site and provide the URL of the site for which the key has to be generated. The key along with an example will be provided which can be used as a base for further developments.

Setting up the map

The Google Maps API library is a JavaScript library. So its focus includes HTML and JavaScript based applications. In other words, the Google Maps API targets the UI for the web applications. To set up the page to display the map the required steps include setting up the HTML page and importing/including the Google Maps API.

Setting up the HTML page

The first step in displaying the map is to provide the required placeholder within the page where the map has to be shown. To do this the <div> tag must be used. It creates a logical block for the display of the map. For example the following statement creates a placeholder named ‘map’:

<div id=”map” style=”width: 500px; height: 500px”></div>

Importing/Including the Google Maps API

To use the API, its library has to be referenced. In the case of JavaScript, importing or including the library (which are just other terms for referencing a library) is done using the src attribute of <script> tag. So to include the Google Maps API library, the src of the <script> tag would be as follows:

<script src=”http://maps.google.com/maps?
file=api&v=2&key=
[yourkey]”
type=”text/javascript”> </script>

The value of the src attribute tells us two important points about the Google Maps API. The first is the location of the API which is Google’s site itself. So even for testing purposes, availability of the Internet is required. The second is the usage of the key provided after registration. The key is passed along with the URL in the src to tell Google that the site trying to access the API library is an authorized site.

The next step is to implement a function that will be called when the document is loaded. That is done by calling a function in the <body> tag’s onload handler. The statements would be :

<script type=”text/javascript”>
//<![CDATA[
function load() {
}
//]]>
</script>

for defining the function. It would be called from the body thus:

<body onload=”load()” >
:
:
</body>

The first step in the implementation of the logic within the function is to check whether or not the client browser is capable of displaying the map. That can be done using GBrowserIsCompatible(). It returns a Boolean value specifying whether or not the browser is capable of displaying the map. The code block using it would be thus:

if (GBrowserIsCompatible()) {
  //…
}

To display the map what we need is an object of the GMap2 class. To get it, we’re required to use the GMap2 constructor with the id of the <div> serving as a placeholder. For example the following code creates an instance of the GMap2 class and assigns it to the variable named map:

var map = new GMap2(document.getElementById(”map”));

The last step in displaying the map is to set its focus on a particular point. That can be accomplished by calling the setCenter() method on the map variable. The argument passed is of the GLatLng type which in turn accepts latitude and longitude as its parameter. The following sets the focus on the point defined by latitude 31.122027 and longitude 77.111664:

map.setCenter(new GLatLng(31.122027, 77.111664), 13);

The map object can be used to manipulate the map by using the methods enumerated in the first section. The last but not least point is to call GUnload() through the onunload handler of the body tag to prevent memory leak:

<body onload=”load()” onunload=”GUnload()”>
:
</body>

That brings us to the end of the third section. In the next section I will develop a small application that will show the different functions discussed in the first two sections and use the steps detailed in this section.

The Google Maps API in the Real World 

Now I will build a small application that displays a map using the Google Maps API. It does the following:

  1. Displays the map with Shimla (India) as its center.
  2. Provides zoom and pan controls for navigation.
  3. Provides a map type control to change between the three map types.
  4. Handles the click event and display information window showing the current focus point upon a click on the map.

So let’s get going. First the HTML setup:

<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Strict//EN”
“http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd”>

<html xmlns=”http://www.w3.org/1999/xhtml”>
<head>
</head>
  <body onload=”load()” onunload=”GUnload()”>
    <div id=”map” style=”width: 500px; height: 500px”></div>
  </body>
</html>

The onload handler calls the load function which is as follows:

<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Strict//EN”
“http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd”>

<html xmlns=”http://www.w3.org/1999/xhtml”>
<head>

<script src=http://maps.google.com/maps?file=api&amp;v=2&amp;key=[yourkey] type=”text/javascript”>
</script>

<script type=”text/javascript”>

//<![CDATA[

           function load() {
}
</script>
</head>
<body onload=”load()” onunload=”GUnload()”>
<div id=”map” style=”width: 500px; height: 500px”></div>
</body>
</html> 

Place the key you received in place of [yourkey]. This sets up the link to the Google Maps API and declares the load function. Next comes creating the map instance and setting the center.

<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Strict//EN”
“http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd”>

<html xmlns=”http://www.w3.org/1999/xhtml”>
<head>

<script src=”http://maps.google.com/maps?
file=api&amp;v=2&amp;key=[yourkey]” type=”text/javascript”>
</script>

<script type=”text/javascript”>

//<![CDATA[

           function load() {
          
if (GBrowserIsCompatible()) {
var map = new GMap2(document.getElementById
(”map”));
map.setCenter(new GLatLng(31.122027,
77.111664), 13);
}

          }
</script>
 

</head>
<body onload=”load()” onunload=”GUnload()”>
<div id=”map” style=”width: 500px; height: 500px”></div>
</body>
</html>

Next we add the controls:

<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Strict//EN”
“http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd”>

<html xmlns=”http://www.w3.org/1999/xhtml”>
<head>

<script src=”http://maps.google.com/maps?
file=api&amp;v=2&amp;key=[yourkey]”
 type=”text/javascript”>
</script>

<script type=”text/javascript”>

//<![CDATA[
function load() {
if (GBrowserIsCompatible()) {
var map = new GMap2(document.getElementById
(”map”));

              map.addControl(new GSmallMapControl());
map.addControl(new GMapTypeControl());
map.addControl(new GScaleControl());

                map.setCenter(new GLatLng(31.122027, 77.111664),
13);
}
}
</script>

</head>
<body onload=”load()” onunload=”GUnload()”>
<div id=”map” style=”width: 500px; height: 500px”></div>
</body>
</html>

The controls have to be added before setting the center. The last part is to handle the click event and show the current focus point on an information window:

<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Strict//EN”
“http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd”>

<html xmlns=”http://www.w3.org/1999/xhtml”>
<head>

<script src=”http://maps.google.com/maps?
file=api&amp;v=2&amp;key=[yourkey]”
 type=”text/javascript”>
</script>

<script type=”text/javascript”>

//<![CDATA[
function load() {
if (GBrowserIsCompatible()) {
var map = new GMap2(document.getElementById
(”map”)); 
 

               map.addControl(new GSmallMapControl());
map.addControl(new GMapTypeControl());
map.addControl(new GScaleControl());

               map.setCenter(new GLatLng(31.122027, 77.111664),
13);

               GEvent.addListener(map,”click”, function(){
                
map.openInfoWindow(map.getCenter(),
document.createTextNode(map.getCenter()));
               
}
              
);
            
}

           }
</head>
<body onload=”load()” onunload=”GUnload()”>
<div id=”map” style=”width: 500px; height: 500px”></div>
</body>
</html>

That completes the application. In just a few lines it does a lot. This was just a teaser of what the Google Maps API can do. In future articles I will discuss advanced features such as communicating with servers and geo-encoding. Till then….

by A.P.Rajshekhar 

Understanding Controllers in Ruby-on-Rails

(No Ratings Yet)
Loading ... Loading ...

In an MVC based web application, it is the controller that orchestrates and controls the flow of application logic. So to create an efficient, scalable and robust application, the clear understanding of the controller component provided by the framework is necessary. RoR is no exception.The Controller component provided by RoR is the ActionController. In this discussion I will focus on the ActionController. The first sections will cover the services provided by ActionController and the techniques to access them. The final section will provide insight into using these techniques in the real world.  So let’s get started.

Into the World of the ActionController

In RoR, the Action Pack forms the core of the framework. It contains two modules, the ActionView and the ActionController. One aspect of the Action Pack is that it cannot be used as a part of anything but a web application. With this in mind let’s look at what happens when a URL such as http://localhost:3000/demo/say/hello is called. As discussed in the previous article, a URL consists of the application name, then the controller name and finally the action name. So what RoR really does when a URL is typed in can be divided into the following steps :

  1. It loads the file say_controller.rb situated in the app/controllers directory. It happens only once in a production environment.
  2. Then RoR instantiates an object of the class named SayController.
  3. Once the class has been instantiated, it looks into app/helpers for a file named say_helper.rb. If it exists, it is loaded and the module SayHelper is mixed into the SayController object. That means the methods of the SayHelper module will be available directly from within the instantiated object of SayController.
  4. It then loads the model from say.rb within the app/models if found.

Now that the sequence of application initialization is cleared, let’s move on to the services provided by the ActionController. The usage of the services will be discussed in detail in the future. The Controller component of the RoR provides the following services:

  1. Routing the requests
  2. Session tracking
  3. Filtering and Verification
  4. Caching

The next obvious question would be “why are all these services provided by the Controller component?” The answer lies with the fact that in an MVC based architecture, the Controller sits at the boundary of the application. Hence it can monitor every kind of data flow within the application and redirect or reroute if required. Many of these “flows” require the tracking of the details of the current user, caching the generated data for performance enhancements, and so on. So the best component to provide these services is the Controller. With that, here are the details.

Routing the Requests, and Session Tracking

1. Routing the requests

If you tried out the application developed in last part, you would remember a URL of the form of http://localhost:3001/admin/show/1/. The question that arises is, how does RoR map such a URL to a specific method or class? The mapping is done by routing the information contained in a file named routers.rb within the config directory. The information would look like the following code:

ActionController::Routing::Routes.drawdo|map|
map.connect ‘:controller/service.wsdl‘, :action => ‘wsdl
map.connect ‘:controller/:action/:id
end

The Routing component of the ActionController creates a map that connects the external URLs to the internals of the application. To make it more clear, look at the third line of the code block. The second map.connect statement contains the string :controller/:action/:id‘. It acts as a pattern to be matched against the path portion of the request URL. In the case of the request URL, the path can again be subdivided into three parts:

a. The first part would be assigned to the :controller part of the pattern.

b. The second part would be assigned to the :action part of the pattern.

c. The third part would be assigned to the :id part of the pattern.

On the basis of the above deduction, http://localhost:3001/demo/admin/1/ would be mapped as:

@params = { :controller => ‘admin’,
:action => ‘show‘,
:id => 1 }

Based on this, RoR would invoke the show method in the admin controller with a parameter for the id of 1. Thus with this simple yet powerful technique, RoR does many things.

2. Session Tracking

Tracking a user across the application is the most required capability for any web application. Tracking can be done, in an efficient way, either by using cookies or session management provided by the framework. RoR provides both of these implicitly without the requirement of using explicit objects by means of the ActionController. Look at the following code block:

  class CookiesController < ApplicationController
def create_cookie
cookies[:the_time] = Time.now.to_s
redirect_to :action =>
“action_two”
end

    def get_cookie
cookie_value = cookies[:the_time]
render(:text =>“The cookie says it is #{cookie_value}”)
    end
  end

In the code above, there are two action methods in the Controller, one that sets a cookie and another that reads the cookie and displays the value. Here cookies[] is an implicit array/list of cookie objects. A new cookie can be added by specifying the name and providing the value.

Next the :action (which is a parameter of redirect_to) is given to the controller to which the request has to be redirected. In this case it is get_cookie action. In the second action the value of the cookie is extracted and shown using the render() method.

That covers cookies. But it is much better if there is a method to implement cookies transparently. That technique is the use of session. Just like cookies, session is also implicit. Its syntax and usage is similar to that of the cookie object. The following code will make it more clear:

  class SessionController < ApplicationController
    def login
user = User.find_by_name_and_password(params[:user], params[:password])
if user
session[:user_id] = user.id
redirect_to :action =>
“index”
else
reset_session
flash[:note] =
“Invalid user name/password”
    end
end

The above code checks the user-id and password. If the user is valid it sets the user-id in session. The statement session[:user_id] = user.id. is the same as setting a cookie. Next the user is redirected to the index page. If the user is not valid, the session is invalidated using reset_session. This again reflects the simplicity of RoR.

Filtering and Verification, and Caching 

3. Filtering and Verification

There are situations where certain processing must be done before a request is serviced. In such situations filters come into the picture. Filters are pieces of code that wrap the logic that needs to be called before or after any number of actions within the controller or its derived classes. There are two kinds of filters, before and after filters. The before filters work before a request has been processed, whereas the after filters do the task after the action has been invoked. For example, if a code for verifying a user’s session must be called before invoking an action, the code would be:

  def authorize
unless session[:user_id]
flash[:notice] =“Please log in”
redirect_to(:controller =>“login”, :action =>“login”)
end
end

  class AdminController < ApplicationController
before_filter :authorize
# …

Here the code to be executed before invoking any action within the AdminController is wrapped inside the authorize function, which is then called before any other action using the before_filter. The after_filter also works in the same way.

Filters can only call a code to be executed, but in situations where the need is to verify that a certain condition is met before an action is executed, filters can’t do much. It is here that verification comes handy. Verification can be done by using the verify. Let’s visualize a situation where the conditions are: the user-id must be valid, the user can only post comments, and if the conditions are met, redirect to the index page. The code using verify would be:

  class BlogController < ApplicationController
verify :only => :post_comment,
:session => :user_id,
:add_flash => { :note =>“You must log in to comment”},
:redirect_to => :index

  # …

Its that easy.

4. Caching

Rendering the same content again and again puts a heavy load on the server. To counter such a case, caching is used. For example, an action render_one that is being called again and again would be a good candidate for caching. Indeed, caching is a requirement here.

In RoR caching can be done using the caching declaration. The caching can be page-level, action level, or both. To cache pages the declaration caches_page has to be used, and to cache actions the caches_action needs to be used. For example, in a blog management application, if the publicly viewable contents have to be cached the code would be:

class ContentController < ApplicationController
  before_filter :verify_premium_user, :except => :public_content
  caches_page :public_content

That ends the overview of the functionalities provided by the ActionController. In the near future I will discuss these in greater depth. But for now let’s move on to the next section, which features an example of using the Controller for processing.

Rails in the Real World 

As mentioned in the previous part, it is still not time for heavy-duty examples. They will be coming once the ActiveView and ActiveRecord have been discussed which will be covered in the near future. For this part, I will extend the example showing the time in the view created in the last part. If you remember, I created a controller having the following code:

  classSayController < ApplicationController
defhello
end
end

and the view(hello.rhtml) having this code:

  <html>
  <head>
  <title>Hello, Rails!</title>
  </head>
  <body>
  <h1>Hello from Rails! The time now is <%=Time.now%></h1>
  </body>
  </html>

But this is a bad design since the code for displaying date(in bold) is within view. View shouldn’t be doing this. So let’s move it to the controller because it is the right place for the code to be:

  classSayController < ApplicationController
     defhello
         @time=Time.now
     end
end

Now the current time value is stored in an instance variable time. Now it can be called from the view thus:

  <html>
  <head>
  <title>Hello, Rails!</title>
  </head>
  <body>
  <h1>Hello from Rails! The time now is <%=@time%></h1>
  </body>
  </html>

That’s it. In the next part I will be looking at the ActionView, the View Component of RoR. From then on I will be discussing the working of a real application, Library Management. Till then…

by  A.P.Rajshekhar 

MS Access - Browser Style Form Navigation

(No Ratings Yet)
Loading ... Loading ...

My last couple of articles have featured a demo app affectionately named Something Not Entirely Unlike Access. The application employs a variety of methods to obfuscate the “Accessian” features. In our last article, we discussed how to automatically resize subforms, the way some browser frames work. This month, we’ll tackle navigation.

Once again, the download is the same as last two month’s. The screen shot below displays the main form in design view, and you’ll notice the Internet Exploreresque Forward and Back buttons in the upper left corner. Programming the logic behind their navigation is this month’s project.

The Easy Piece

Let’s get the easy piece out of the way. The form has at least three buttons: one to navigate back, one to navigate forward, and a Home or Start Page button. The images were easy to create using MSPaint and a screen shot of Internet Explorer. Once you have an image you like, just assign it to the [Picture] property of the button.

As shown in the screen shot, I’ve used the technique whereby I assign a public function to the OnClick event. (A public sub should work in newer versions of Access, but I believe even Access 2000 would not recognize the assignment unless it was a Function, not a Sub.) So by clicking the back button, a function on frmMain called MainNavBack() is executed. The code for these functions, MainNavBack() and MainNavForward(), is shown below.

Each of these functions calls another function on frmMain named LoadMainSubform(). This process was described in our first article, which introduced the Something Not Entirely Unlike Access application. Accordingly, we won’t go into detail on what this function does, but suffice it to say that, given the name of a form, it loads and resizes that form into the single subform object on frmMain, effectively changing pages.

This month’s trick will be logging page visits and then determining the correct page to load when users click Back or Forward. To do this, we create and implement our own navigation class, named clsNavigation. We’ll show the code for the class a little later, but first let’s show how it’s used. Implementation in the form requires these steps:

  1. Declare a module level object of type clsNavigation using the NEW modifier.
  2. Call the object’s Load method in the form’s Open event.
  3. For each new page, call the object’s AddNavPage method to log the visit.
  4. Create a function to call the object’s NavPrevPage method to find the previous page.
  5. Create a function to call the object’s NavNextPage method to find the next page.

That’s all we have to do on the form. Our work is done here. The real logic exists in the class, clsNavigation. So long as you have the above five steps implemented correctly in the form, everything else depends on the class module, which you may freely import into your application from the download code. You’ll need to tweak it a little to get it to work, but it’s all there, and more.

dl_browsernav_image001.jpg

    ‘ First, create a module level navigation object of
    ‘ type clsNavigation.  (this class does not yet exist
    ‘ … we will be building it shortly.)
    Private m_objNav As New clsNavigation

    Private Sub Form_Open(Cancel As Integer)
        On Error GoTo Err_Handler

        ‘ Create class to manage navigation controls
        m_objNav.Load

        ‘ do other Form Open stuff here …
    End Function

    Public Function MainNavBack() As Boolean
        On Error GoTo Err_Handler
        Dim strPage As String

        strPage = m_objNav.NavPrevPage
        Call LoadMainSubform(strPage, False)
    Exit_Here:
        Exit Function
    Err_Handler:
        MsgBox Err.Description, vbCritical
        Resume Next
    End Function

    Public Function MainNavForward() As Boolean
        On Error GoTo Err_Handler
        Dim strPage As String

        strPage = m_objNav.NavNextPage
        Call LoadMainSubform(strPage, False)
    Exit_Here:
        Exit Function
    Err_Handler:
        MsgBox Err.Description, vbCritical
        Resume Next
    End Function

    Public Sub LoadMainSubform(ByVal sFormName As String, _
                               ByVal fLogNav As Boolean    )
        On Error GoTo Err_Handler

        ‘ Update the navigation object with the new page,
        ‘ unless the LogNav flag is set to False. This
        ‘ give you flexibility to skip logging for some pages.
        If fLogNav = True Then m_objNav.AddNavPage sFormName

        ‘ continue with process of loading form …
    End Function

Creating and Loading The Navigation Class

Technically, the Navigation class is created above in the declaration. When the module level variable, m_objNav, is declared with the New modifier, the class is instantiated and ready to use. Because it is a module level variable, it persists as long as frmMain is open.

To build the class, you need to select Class Module from the Insert menu option. A Class module is different from a Standard module, so be sure that all the code that follows goes into a Class Module. When the above-mentioned variable, m_objNav, is declared, an instance of the class is created. (Notice that the icon for a Class module is different from the icon for a Standard module.)

dl_browsernav_image002.jpg

While an instance of the class may exist in m_objNav, it can’t really do anything until the Load method is called. Loading the class does little more than create an in-memory ADO recordset, into which we will load our data. The code looks like this …

Option Compare Database
Option Explicit

Private c_rstNav As ADODB.Recordset
Private c_intCurrItem As Integer
Private c_intMaxItem As Integer
Private c_fMovedBack As Boolean

    Public Sub Load()
        On Error GoTo Err_Handler

        ‘ Instantiate the private level ADO recordset object, add
        ‘ as many fields as you’d like, and load the first record.
        Set c_rstNav = New ADODB.Recordset
        With c_rstNav
            .Fields.Append “ItemID”, adInteger
            .Fields.Append “Value”, adVarChar, 64
            .Fields.Append “CustomerID”, adVarChar, 5
            .Fields.Append “EmployeeID”, adInteger
            .Fields.Append “ProductID”, adInteger
            .Fields.Append “OrderID”, adInteger
            .Fields.Append “URL”, adVarChar, 512
            .Open

            ‘ Note that I have added various IDs to the recordset.
            ‘ These will be used to load the correct record.
            ‘ I always include functions to set and get these IDs.
            ‘
            ‘ This could be recoded to be more flexible, but since
            ‘ the demo app uses this format, I’ll let it be for now.

            .AddNew
            !ItemID = 0
            !Value = “frmStartPage”
            !CustomerID = GetCustomerID()
            !EmployeeID = GetEmployeeID()
            !ProductID = GetProductID()
            !OrderID = GetOrderID()
            .Update
        End With

    Exit_Here:
        Exit Sub
    Err_Handler:
        MsgBox Err.Description, vbCritical
        Resume Next
    End Sub

The class is now loaded. The private ADO recordset, c_rstNav, exists and contains a single, initial record. This recordset will persist so long as the class persists. The class persists as long as the form is open. So, we’ve created a little in-memory log book of the pages visited by our user.

Adding a Page

The next action we need to code is the adding of a page. Of course, we need to log the page’s name, but we’re also going to need some additional information. For example, if we just navigated to frmCustomer, we’re also going to need to know WHICH customer, that is, what was the CustomerID at the moment the form was loaded?

Once again, having considered my previous articles would be of benefit, but in a nutshell, here’s how I load forms: When the user double-clicks on, for example, the row of the Customers List Subform, the current row’s CustomerID is saved by means of the SetCustomerID() public function. When the form is loaded, it uses the GetCustomerID() method to determine which record to load. So, at the time the page is “navigated to,” the CustomerID is known and can be persisted in our navigation object. The same is true for EmployeeID, ProductID, OrderID or URL, if the form is loading a web page.

Now, I should be ashamed of myself for this clumsy and non-extensible code. It would have been much better to have only two columns: KeyFieldName and KeyFieldValue. These could be reused more efficiently. When the frmCustomer is loaded, the [KeyFieldName] would be set to the text “CustomerID” and the [KeyFieldValue] to its value. When frmEmployee is loaded, [KeyFieldName] would be “EmployeeID” and [KeyFieldValue] would contain the current EmployeeID. This would have been smart, but as it turns out, that’s not how the demo code works, so I won’t bother tweaking it now, but as you can see from the code below, it’s pretty simple to modify this navigation recordset. Add and/or remove fields as you wish. Play with it … it’s fun.

The AddNavPage() method has some tricks to it. First, the argument, sValue, must exist. This part of the code could be smarter too, by checking to see that a form actually exists by the name passed in sValue.

In order to behave as Internet Explorer does, the FlushForward method must be called each time a page is added. It basically resets the recordset to make the current page the last record. It’s like with IE (or any other browser) when you navigate back three or four pages, and then go to a new page. The browser dumps any knowledge of those pages and starts off on a new path, with the current page becoming the last in the string of pages.

Next the c_rstNav recordset object is manipulated to locate our starting point, the last ItemID and value in its set. The strLastValue variable is used to avoid adding rows for the same page multiple times. (The Refresh or Requery action of the form may trigger this method and we don’t need to log those events.) I’ve also added a condition to allow for logging of multiple pages so long as the form is frmIE, which is a browser control.

Once the record is successfully saved, we increment the class variables c_intMaxItem and c_intCurrItem, which will be used later when locating the requested navigation page. At this point, our page is logged in the recordset, and the class properties are set.

Public Sub AddNavPage(ByVal sValue As String)
        On Error GoTo Err_Handler

        Dim intLastItem As Integer
        Dim strLastValue As String

        If Trim(sValue) = “” Then
            Exit Sub
        Else
            Call FlushForward

            With c_rstNav
                If Not .EOF Then .MoveLast Else .MovePrevious
                If Not .BOF Then
                    intLastItem = !ItemID
                    strLastValue = !Value
                End If

                ‘ Always log IE browser pages.
                If sValue <> strLastValue Or sValue = “frmIE” Then
                    .AddNew
                    !ItemID = intLastItem + 1
                    !CustomerID = GetCustomerID()
                    !Value = sValue
                    !EmployeeID = GetEmployeeID()
                    !ProductID = GetProductID()
                    !OrderID = GetOrderID()
                    !URL = GetURL()

                    On Error Resume Next
                    .Update
                    If Err.Number = 0 Then
                        c_intMaxItem = c_intMaxItem + 1
                        c_intCurrItem = c_intMaxItem
                    End If
                End If
            End With
        End If

    Exit_Here:
        Exit Sub
    Err_Handler:
        MsgBox Err.Description, vbCritical
        Resume Next
    End Sub

Retrieving A Page

The code for NavNextPage is shown below, but NavPrevPage is nearly identical. All this code needs to do is locate the previous or next record in the recordset and extract the form name and associated IDs. This is where that class variable, c_intCurrItem, comes into play. The Find method is used with the c_rstNav recordset to locate c_intCurrItem. Once found, the values of the row are read and the form name is returned by the function.

    Public Function NavNextPage() As String
        On Error GoTo Err_Handler

        Dim strOut As String

        c_intCurrItem = c_intCurrItem + 1
        If c_intCurrItem > c_intMaxItem Then
            c_intCurrItem = c_intMaxItem
            strOut = “-1″
        End If

        With c_rstNav
            If Not .BOF Then .MoveFirst
            .Find “[ItemID]=” & c_intCurrItem
            If Not .EOF Then
                strOut = !Value
                SetCustomerID Nz(!CustomerID, “”)
                SetEmployeeID Nz(!EmployeeID, 0)
                SetProductID Nz(!ProductID, 0)
                SetOrderID Nz(!OrderID, 0)
                SetURL Nz(!URL, “http://www.amazecreations.com/datafast/”)
            End If
        End With

    Exit_Here:
        NavNextPage = strOut
        Exit Function
    Err_Handler:
        MsgBox Err.Description, vbCritical
        Resume Next
    End Function

Final Thoughts

In reviewing the code, I can’t help but think that I’ve over-complicated the process and over-simplified the explanation. That having been said, I still think this code may be of benefit to readers. It can be improved upon, it’s true and it will take some concentration to read and understand all that is taking place, but that’s what programming is about. It’s not perfect, but it’s a start.

by Danny Lesandrini

Auto-Resize Access Subforms In MS Access

(No Ratings Yet)
Loading ... Loading ...

In the last article we introduced the application we’re calling Something Not Entirely Unlike Access, which simulates some aspects of a web browser in Microsoft Access. This article will focus on the process of resizing subforms on the main form, and the download is the same as last article’s. The screen shot below displays four subforms:  two wide ones on the left, and two narrower ones on the right. In this example, all four have the same height, but as you’ll see, that too is adjustable.

sneua_th.jpg

Resize Subform Objects Code

Jumping right into the code, you’ll notice that every form includes a public function named ResizeControls() which accepts two arguments: lObjWidth and lObjHeight. This function is called by the PARENT form, and the values passed are determined by Form properties called InsideWidth and InsideHeight. You will need to adjust the Height by subtracting the Form Header and Footer space, as that is part of the inside Height. It looks som