Chorn Sokun's Weblog

Conquer inner fear, push it to the limit!

Posts Tagged ‘MonoRail

jQuery ajaxform generate on the fly

with 2 comments

What scripting language would come to your mind first when you begin to talk about client-side scripting (web)? Don’t tell me it is VBScript or I’ll LOL, and so your answer would be? “JavaScript” alright +1 from me :). I believe most of the programmer who is reading this post knowing/aware of jQuery.

I can extend the talk about jQuery into a series of posts but I am not gonna do that because google would give you millions of result about jQuery and it usage.

Today what I am interested to talk about is using jQuery ajax functionality in conjunction with Castle.MonoRail to generate HTML Form on the fly and the form will also has ajax functionality. What does it mean? well let us all get into application context of adding new customer. In general we are going to have a customer page /customers which list all existing customers in a table format. Additional customer can be added by clicking on Add New Customer link wired up with a javascript function.


<a href='#' onclick='addNewCustomer()'>Add New Customer</a>

and the addNewCustomer() function looks like this:

<script language="javascript"> 

function addNewCustomer(){

   $.ajax({
      dataType: 'script',
      url: '/customers/addNewCustomer'
   });

}

</script>

From the above script the web browser going to send off a request to /customers/addNewCustomer which is going to handle by an action of CustomersController. If you care to see the action code it look like this:


[Layout("default"), Rescue("generalerror")]
public class CustomerController: SmartDispatcherController
{
    .... code removed for clarity 

    public void AddNewCustomer(){

        PropertyBag["c"] = new Customer();

    }

    .... code removed for clarity

}

and the rest of the work will be left over to the view engine to find the view template file and process it. Since I am a big fan of Brail View Engine the template file would be call AddNewCustomer.brail and the code look like this:


<form id='form1' method='post' action='/customer/create'>

   Name: ${Form.TextField("c.Name")}
   Phone: ${Form.TextField("c.Phone")}
   <input type='Submit' value='Create New' />

</form>

<script type='text/javascript'>

   $(document).ready(function(){

      $('#form1').ajaxForm( { dataType: 'script' } );

   });

</script>

Again it just simple HTML markup mixed with a few Brail’s tagging macro but take a closer look at the javascript code at bottom, what does it do? Well the idea is once the template is processed it going to generate a pure HTML form and send it back to the client side, however the javascript that send along will ensure that the new generated HTML form will perform a post back via jQuery ajax functionality. Hmm, sound cool. But didn’t I just waste a bytes of data with this approach? I tell you what, this application is going to run on a LAN so bandwidth is not a problem.

Up to this point everything works perfect, except for one final click on the Submit button to save new customer and oop! look there is a post without ajax It just work as normal as any other HTML form submission. Hmm, what I had discovered was by generating form id=’something’ or whatever as long as it is not id=’form1′. The submission of the form will route through ajax weir isn’t it? I haven’t investigate into jQuery code just yet jQuery might use form1 for something else internally, do you know what it is?

UPDATE 2008-11-25:

I believe my first assumption about form id attribute which cause ajax not to fire was wrong. What I recently found was if I am not calling $(document).ready(…); in the original page the generated dom pass in even if it contain $(document).ready(…) script block that block just do nothing.

Advertisements

Written by Chorn Sokun

September 21, 2008 at 9:27 pm

Posted in OSS, Programming, Tips & Tricks

Tagged with , ,

REST, Routing & the beauty of MR Controller

with one comment

What is REST?

REST stands for Representational State Trasfer an important concept in REST is the existence of resources (sources of specific information), each of which is referenced with a global identifier (e.g., a URI in HTTP).

How does it work?

REST take advantage of HTTP methods such as POST, GET, PUT and DELETE and translate the request as CREATE, READ, UPDATE, DELETE (CRUD) operation associated with database technologies.

HTTP CRUD
POST Create, Update, Delete
GET Read
PUT Create, Overwrite/Replace
DELETE Delete

REST application might define resources URI such as:

http://example.com/albums
http://example.com/albums/id
http://example.com/albums/id/slideshow

and client code would look something like this:

Resource userResource = new Resource('http://example.com/users/001');
userResource.delete();

It is simple enough, right?

RESTful Castle

REST needed URI to begin with; now if you are assigned to design a server side code for that what are you gonna do? Well, you simple need an URL Rewrite tools to save day, don’t you? So what does URL Rewrite tools do? Simply it would intercept incoming HTTP request and route to relevant destination (.php, .cgi, .aspx, .asmx scripts etc). It is pretty trivial to do it on apache web server:

  1. Make sure mod_urlrewrite is enabled
  2. define a few rules in .htaccess (hmm, regex not so funny)
And that all you need. But I am not talking about Apache I am now going to talk about .NET and the IIS to be exact I am talking about Castle.MonoRail. Castle.MonoRail is a MVC framework (MVC stands for Model-View-Controller) and I am going to dive a bit into Controller. According to the document a Controller logically grouped in an Area; and it contains Actions. For instance to produce url like this /admin/users/index.rails we simple define a controller class as:
[ControllerDetails(Area="admin")]
public class UsersController : Controller
{
   public void Index()
   {
   }
}

Notice the use of ControllerDetails attribute which usually allow you to tell MonoRail how a controller can be found. The important part of ControllerDetails above is Area = “admin” which is very flexible and that mean you can burried a controller down as deep as you want it to be.

Is that mean I can have a controller defined and it will generate URI like this?

http://example.com/albums
http://example.com/albums/id
http://example.com/albums/id/slideshow

With controller alone? you basically can’t do, because controller generated URI in the form /area/controller/action.rails?id={id} to do a nice RESTful like URI you need another tool similar to URL Rewrite lucky enough MR got a build-in tool for that it located here Castle.MonoRail.Framework.Routing … going to talk more in the future.

Limitation & Workaround

How are you going to define your controller class to fullfill the required like this?

* Public Access
http://example.com/albums
http://example.com/albums/id
http://example.com/albums/id/slideshow

* Authorization Access
http://example.com/users/albums
http://example.com/users/albums/id
http://example.com/users/albums/id/slideshow

Look at the screenshot bellow:

and you say; hell YEAH that neat right; now compile and run the test site. Navigate to /album/index.rails work unfortunately navigate to /users/albums/index.rails will cause MR to throw an exception say it can’t find Area & Controller specified.

What the hell ??? the truth is MR register a controller using class name as a key I believe it run from the top namespace first which mean Basic.Web.Controllers.AlbumController got register first so when it walk into Basic.Web.Controllers.Users.AlbumController it just skip that controller.

To work around this problem against thank to ControllerDetailsAttribute which allow us to name a controller free from Controller class. How are you going to do that? well rename /users/AlbumController.cs to /users/WhatTheF_CKAlbumController.cs and boom it done.


[ControllerDetails("album", Area="users")]

public class WhatTheF_CKAlbumController{

    ... same code old code

}

Get lost? probably :) but don’t worry I am going to give a slow version in my C# lecturing session and if you are interested to walkin and listen up just subscribe to my google calendar.

Until then have a good weekend.

Written by Chorn Sokun

September 20, 2008 at 6:01 am

Posted in MonoRail, OSS

Tagged with , ,

Castle.MonoRail.Framework.IFilter – Part I

leave a comment »

Today I would like to share some technique in using Castle.MonoRail.Framework.IFilter . I am a bit sad because it takes too much time for me to realize how useful, until I read between the line over and over again

Filters are executed before and|or after your actions. It is useful for security, dynamic content and to keep away repetitive code.

Keep away repetitive code is what I am tracing, let the hear the story shall we?

This happen with one of the real world project that I am working on Data Bridge like any other web application it need authentication and passing some user preference along each action (inherit from SecureController) to the view such as List, Add, Edit & Delete action & view.

This can be done using the following technique:

Create Filters\AuthenticationFilter.cs

public class AuthenticationFilter: IFilter
{
 bool IFilter.Perform(ExecuteEnum exec,
     IRailsEngineContext context, IController controller)
 {
   if( !UserNotLogin() ) {
       Redirect("Login", "Index");
   } else {
       controller.PropertyBag["maxRow"] = GetUserMaxRowPreference();
       //... set more preferences as needed
   }
 }
}

Create SecureController

[Layout("default"), Rescue("generalerror")]
[Filter(ExecuteEnum.BeforeAction, typeof(AuthenticationFilter))]
public abstract class SecureController : ARSmartDispatcherController
{
    // ... more code
}

SecureController is marked as abstract, prevent from direct use.

Using SecureController

public abstract class ProductController: SecureController
{
    public void List() { //... list action code }
}

Now view part: View\Product\list.vm
When render table I want to display miximum $maxRow rows.

See there is no code need to set preference in each action method, nice.

Written by Chorn Sokun

December 31, 2007 at 3:14 pm

Posted in Castle, MonoRail

Tagged with ,