Castle Demo AppLet There Be A New User

time to read 33 min | 6566 words

Before we start with our regular content, a couple of bug fixes, the ValidateLength on the Name and Email properties of the User class should looks like this: 

[

ValidateLength(0,50)]

Specifying just one number means the exact length of the string.

Okay, so far we have seen how to edit users and then save them to the database, but we haven't seen yet how to actually create the users. For myself, I think the users will be less than inclined to add themselves to the database by hand, using SQL, and I can just imagine the expression on the face of the DBA when he hears this suggestion.

Okay, I hear you, I won't bring that up again, looks like we have to do some work to make it happen. The question is, how much work is needed? We did a fair amount of work yesterday, to support editing users, how much of this work do you think we can use to support creating users?

Before anything else, I'm getting tired of having to remember all those URLs in my head, we'll add an index page to our administration section. Add an empty method called Index() to the AdminController class and create the following view at Views\Admin\Index.boo

<ul>

  <li>

    ${HtmlHelper.LinkTo('Admin Projects','projects')}

  </li>

  <li>

    ${HtmlHelper.LinkTo('Admin Users', 'users')}

  </li>

</ul>

Now we create the CreateUser method:

    public void CreateUser()

    {

        RenderView("EditUser");

    }

In the EditUser.boo view, we need to make a single change, and that is to initialize the id varaible to "0" instead of empty string, like this (fragement):

<?brail

      name = ""

      email = ""

      id = "0"

Let's beef up our SaveUser method, to make it capable of handling both existing and new users, the new stuff is bolded:

    public void SaveUser([ARDataBind("user",AutoLoadUnlessKeyIs=0)]User user)

    {

        RenderView("GenericMessage");

        try

        {

            user.Save();

            Flash["good"] = string.Format(

                "User {0} was saved successfully.", user.Name);

        }

        catch (Exception e)

        {

            Flash["DataBindErrors"] = user.ValidationErrorMessages;

            Flash["bad"] = e.Message;

        }

    }

I added some better handling for errors, and we now direct the framework to automatically load the user from the database unless the id is equal to 0. I think that this may require a couple of changes to the GenericMessage view, like this:

<p>

<font color="red">

<?brail

 if IsDefined('bad'):

  output bad

 end

?>

</font>

</p>

<?brail if IsDefined('DataBindErrors'): ?>

<table>

      <tr>

            <thead>Validation Errors</thead>

      </tr>

      <?brail for error in DataBindErrors: ?>

      <tr>

            <td>${error}</td>

      </tr>

      <?brail end ?>

</table>

<?brail end ?>

<p>

      <font color="green">

      <?brail

      if IsDefined('good'):

        output good

      end

      ?>

      </font>

</p>

Okay, we're done with creating users. Play with it a bit, try to add a non email adress, put it strings that are too long, use names that already eixst, etc. I won't claim that this is the greatest UI in the world, but it's functional.

Next stop, deleting users, should be simple. For now, we'll build it using normal pages & post backs. In a short while, I'll see how to use the Ajax support in MonoRail. We'll start by editing the users.boo page to add a link to the delete page, like this (fragement):

    <td>

      <?brail

        output HtmlHelper.LinkTo("Delete","admin","ConfirmDeleteUser",user.Id)

      ?>

    </td>

As long we're on a roll, we'll add a link to the create user page, like this (fragement):

${HtmlHelper.LinkTo('Create New User','admin','CreateUser')}

Now we get to write the delete functionality itself. We'll start with Views\Admin\ConfirmDeleteUser.boo, which looks like this:

<p>

  ${user.Name} says he is sorry, are you still angry?

</p>

<p>

      ${HtmlHelper.LinkTo('Yes, Delete!', 'Admin', 'DeleteUser',User.Id)} 

<p>

</p>

      ${HtmlHelper.LinkTo('Well, no...', 'Admin', 'Users')} 

</p>

And now to write the code that will actually handle all of this. Here it is in full:

    public void ConfirmDeleteUser([ARFetch("id",Create=false)]User user)

    {

        if (user == null)

        {

            RenderView("NoSuchUser");

            return;

        }

        PropertyBag.Add("User", user);

    }

 

    public void DeleteUser([ARFetch("id", Create = false)]User user)

    {

        if (user == null)

        {

            RenderView("NoSuchUser");

            return;

        }

        user.Delete();

        RedirectToAction("Users");

    }

This require some explanation. The ARFetch attribute will take an id and will pull it out of the database and into our parameter (passing null if it can't find it). We just make sure that it is handled properly. This is it, we know has full CRUD for a user. I'm going to leave the implementation of similar operation for projects as an exercise for the reader.

Next time, we'll see how we can add some Ajax stuff to it, so we can keep up with the hype.

More posts in "Castle Demo App" series:

  1. (03 Mar 2006) ViewComponents, Security, Filters and Friends
  2. (01 Mar 2006) Code Update
  3. (01 Mar 2006) Queries and Foreign Keys
  4. (28 Feb 2006) Complex Interactions
  5. (25 Feb 2006) CRUD Operations on Projects
  6. (22 Feb 2006) Let There Be A New User
  7. (22 Feb 2006) Updating our Users
  8. (20 Feb 2006) Getting serious, the first real page
  9. (20 Feb 2006) MonoRail At A Glance
  10. (20 Feb 2006) The First MonoRail Page
  11. (19 Feb 2006) Many To Many Relations
  12. (19 Feb 2006) Lazy Loading and Scopes
  13. (17 Feb 2006) Active Record Relations
  14. (17 Feb 2006) Getting Started With Active Record