WebObjects on Rails

"Pierce T. Wetter III" <[email protected]>
Newsgroups gmane.comp.web.webobjects.devel
Message-ID <[email protected]>
The Ruby On Rails book has inspired me to share some of the tricks  
I've learned over the years to make WebObjects more streamlined.

Let's start with the following:

public class EZDirectAction extends DirectAction {

	public EZDirectAction(WORequest aRequest) {
		super(aRequest);
	}

	public WOActionResults performActionNamed(String name) {
		EZPage nextPage=(EZPage) pageWithName(name);
		nextPage.takeFormValues(request().formValues());

		return nextPage;
	}
}

public class EZPage extends EZComponent {

// better solution is actually to have EZComponent implement the
// EOKeyValueCodingAdditions protocol, then this is one line
// self.takeValuesFromDictionary(values)

	public void takeFormValues(NSDictionary values) {

	java.util.Enumeration enum=values.getValueList().objectEnumerator();
	while (enum.hasMoreElements()) {
		String key=(String) enum.nextElement();

		Object obj= values.valueForKey(key);
		if (obj != null) {
			self.takeValueForKey(obj,key);
		}
	}
}

Ok, now this code is making only one assumption, and its a good one:

  a. All your _page_ components are subclasses of EZPage.

What this code does is enable direct actions for every single page in  
your WO application, _without any additional coding_. All you have to  
do is add it to the project and your application will automatically  
understand URLs of the form:

/wa/MyPage?valueS=1&value2S=2

This is doing a bit of voodoo if you're not familiar with the ins and  
outs of
the lower levels of the the WO frameworks, but basically the code  
does two things.

First, rather then use the default behavior of "performActionNamed",  
which appends "Action", and then looks for a method of that name, we  
simply map pages to action on a 1-1 basis (which is what you do 99.9%  
of the time anyways).

Now WO doesn't really make a distinction between pages and  
components, but we'll do it here for simple security reasons because  
we don't necessarily want users to be able to pull up arbitrary bits  
of the application (even though /wo/Component.wo works in most WO  
apps anyways). Plus I've always found that pages function as a  
controller in the MVC paradigm anyways so you end up needing things  
at the page level you don't need at the component level. So its  
incredibly useful to have cross-application base classes for both  
your components and your pages.

Then, although its calling "form values", what that's really doing is  
pulling all of the key-labeled strings out of the URL and shoving  
them into the page using key-value-coding. WOComponent doesn't  
implement EOKeyValueAdditions, so you can't just shove in the whole  
dictionary in one line, you have to walk through the dictionary and  
shove them in one by one instead.

So if "MyPage" above takes two parameters, rather then have to  
explicitly do any initialization in the direct action, what I instead  
do is write a method like the following:

public class MyPage extends EZPage {

    public void setValueS(String s)
    {
	self.setValue(s.toInteger())
    }
}

That is, what happens is that all values in URLs are string, rather  
then integers, or whatever. So if you have string parameters, you're  
done, but if you have non-string parameters, you have to convert them  
as part of the key-value-coding process.

If your page is tied to an EO object its not much more complicated:


    public void setKeyS(String s)
    {
	self.setValue(EOUtilities.objectWithPrimaryKeyValue(
		self.session().defaultEditingContext(),
		"MyObject",s.toInteger())
    }

In fact, if you like, you can sometimes put that code in your page  
baseclass
so that its only in one place. Or perhaps all the pages that can inspect
a particular type of object will have a superclass with that method.

Ok, not much code, and the payoff is that now you can write links as  
follows:

link: WOHyperlink
{
    directActionName: "MyPage";
    ?value1S=value1;  // URL generation converts value[12] to a string
    ?value2S=value2;
    ?keyS=object.key; // grab the primary key
    ?wosid=NO; //assuming you're using cookies
}

Which means you no longer have to craft an action for 99% of the  
links on your site, because most of the time you're just going to  
just going to link to a specific object. And your links will be  
bookmarkable, etc.

So no more links like this:

https://jobs.apple.com/cgi-bin/WebObjects/Employment.woa/1/wo/ 
fpzfbEkBBR22HLXV28KMDg/5.34.33.29.3.3.1.1.1

  Ok? :-)

Pierce
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.