Articles by corprew

You are currently browsing corprew’s articles.

Over the last month, I’ve been learning a lot of things and stuff by participating at stackoverflow.com daily, and I am slowly growing obsessed with it. The ‘help/learn/repeat’ cycle that they have is pretty well optimized for my learning style.

I’ve even had decent luck recommending it to other people; more and more of my relevant search results for dev-relevant things were appearing there, so eventually I signed up and I’m happy I did.

Tags: , ,

So, I’ve based a couple of apps on a combination of authlogic and the iPhone Objective Resource package, and when I mentioned this on the relevant lists I got a bunch of people asking me questions, so I thought I’d post about what I did generally.

There are a couple of steps, most of which are geared towards having authlogic not produce redirects and instead produce http status codes that are interpretable to the applications. Here’s an example of what I mean from my ApplicationController on an app

  def require_user
    unless current_user
      store_location
      flash[:notice] = "You must be logged in to access this page"
      respond_to do |format|
        format.html { redirect_to new_user_session_url }
        format.xml  { render :text => "you must be logged in to access this page.", :status => :unauthorized }
      end
 
      return false
    end
  end

In the default implementation of this filter, it always returns a redirect. ObjectiveResource can follow the redirect (if you have a recent enough version), but it doesn’t really do it a lot of good. This way, you get a status code that you can use.

Since Authlogic focuses on RESTful creation of things, a lot of operations map naturally. To create an account on the Rails app, create a User object, and to test whether the user can log in, create a user session. My application stores credentials between iPhone App invocations, so it creates a UserSession at startup if you have stored credentials.

- (void)applicationDidFinishLaunching:(UIApplication *)application {
//
// ... blah blah blah all sorts of stuff removed.
//
 
	UserPrefsManager* prefs = [UserPrefsManager sharedInstance];
 
	if ([prefs isLoggedIn]) {
		UserSession * us = [[[UserSession alloc] init] autorelease];
 
		us.login = [prefs username];
		us.password = [prefs password];
 
		NSError * err = nil;
 
		if(![us createRemoteWithResponse:&err])
		{
//
//  ... my actual detection stuff removed and just the default left ...
//
			[AlertHelper showAlertWithError:err];
			[prefs clearLogin];
		}
	}
	[ObjectiveResourceConfig setUser:[prefs username]];
	[ObjectiveResourceConfig setPassword:[prefs password]];
//
// ... and proceed on with your app's normal course of things ...
//	
    [window addSubview:tabBarController.view];
}

You see here that i’m creating an UserSession here and testing to see if it works and setting the ObjectiveResourceConfig properties if it does. I have some logic where if there isn’t saved credentials you will get a dialog asking you to login or create an account (or whatever) later on, which is the point of [prefs clearLogin];. This is matched by a change to the create method of the UserSessionController:

      respond_to do | format |
        format.html do
          flash[:notice] = "Login successful!"
          redirect_back_or_default account_url
        end
        format.xml do
          render :xml => @user_session, :status => :created
        end
      end

(For brevity, I’ve just shown the successful branch)

This should be enough to get people going — all the other changes you have to make can be figured out from these two statements, and when I have some spare time I’m going to create a version of the demo application that works with ObjectiveResource. The only other suggestion I have is to use the withResponse: versions of everything and code defensively, and note that in some versions of ObjectiveResource getting an error from your application will cause the application to throw. In the meantime, feel free to ask me any questions

Tags: , , , , , ,

ebooks

So, I’m currently making ebooks for people, and it’s come up enough that I thought I should make it generally known that I’m doing so. I’ve been doing this more or less since the mid-90s when I was working part time at a scientific press (which is how I got involved in early HTML standards efforts.)

I’m also doing some other ebook related things, but I thought I’d mention this on my blog because a lot of my friends are authors, writers, and &c, and they’ve been turning around and telling their friends, &c, &c, and it’s become clear I should link up those two efforts. I’m currently extending and redesigning the cuneiverse website as well.

Hey folks, I’ve been working on a couple iPhone applications recently, and things are at the point where I could use a couple beta users. If you’re interested in any of these, let me know by commenting or emailing me — email temp200911@corprew.org. You can also use the contact page at corprew.org.

  • I’m looking for some users for App A, and it would help if you lived in the Seattle or Portland area and had Celiac disease for this one to be helpful for you (and for you to provide useful data for me.)
  • I’m looking for some users for App B, mostly for people who travel a lot. If you’re traveling by air this holiday season, you’re welcome to give it a shot.
  • I’m also testing a game for the iPhone. For this, it would be handy if you lived in the Capitol Hill region of Seattle and liked fun. As strange as it seems, some people don’t like fun. This should be fun.

All of these are useful and/or fun. Android versions will be coming relatively soon after the iPhone versions, ideally.

soa / drupal

Drupal has a module for doing SOA that is about to be available in αlpha release.

This is a trivial something that seems to come up staggeringly often when translating design to implementation in word press sites, so I thought I’d post it up here so I don’t have to recreate from scratch next time I need it.

So, you have a long, carefully contrived, SEO-friendly title for your pages (or really just a minimally descriptive one), but you don’t want that to show up in the navigation menus. There are a variety of complex ways to fix this, but one of the easiest is to use code like the following:

< ?php 
    $pages = get_pages("parent=0"); # returns parent pages
      foreach ($pages as $x_page) {
        $option = '<li><a href="'.get_page_link($x_page->ID).'">';
        $short_title = "";
        $short_title = get_post_meta($x_page ->ID, "nav_title", TRUE);
        if ($short_title == "")
                $option .= $x_page->post_title;
        else
                $option .= $short_title;
        end;
        $option .= '</a>';
        echo $option;
  }
 ?>

This usually ends up in header.php, and is a good patch for the problem. There are a couple of plugins that attempt to work around this by detecting whether or not you’re in the loop (the loop being the name for the main part of post/page printing), but invariably widgets screw this up somehow, and this solution seems to work a bit better for me, especially for a navigation header (hence the name.)

Tags: , ,

Classy

I’m developing an online class about categorizing web content, mostly aimed at users of content management systems. If you’re interested in being part of the trial audience for this class, comment or contact me. Ideally, this will be a series of short videos each of which will be on some particular topic.

Tags: ,




My bag

Originally uploaded by Corprew / Zeitgeist

Examine the contents of this bag.

Rubber Duck Regatta in Cal Anderson Park’s fountain tonight at 7pm. I’ll hold another next week as well.

There are a variety of duck vendors in town for those who wish to ‘prepare.’ Archie McPhee’s come to mind. Check your bathtub for suspects as well.

There will be round robin with ducks, and also heats for any sort of random things that people want to enter into the competition.

The rules:
1. ducks get put into the fountain
2. ducks float downstream through all the rocks and bricks.
3. eventually, a duck reaches the end.

Isn’t that just… ducky.

This will happen again in a couple of weeks. A more exotic web page to follow after we try this and see what kind of web page it needs.

I’m making this post to elucidate some conversations I had late night last night, none of this is particularly rocket science or necessarily even model rocket science. One hilarious thing that keeps coming up is federating search — combining search results from multiple datastores, which is a moderately hard problem to come up with a general solution for, but relatively easy (frequently) to come up with a solution for a particular purpose.

Complicated general solutions (such as that found in GeoNames for a lot of content information, but it doesn’t federate that with other results and uses a couple of other data sources that aren’t relevant to this.)

Here’s the (relatively trivial) code that does ‘content’ (normally: fulltext but in content management systems called ‘content search’) searching.

module Contentsearch
  module ClassMethods; end
  def self.included(klass)
    klass.extend(ClassMethods)
  end
 
  def ft_index
    logger.debug("[contentsearch::ftindex] submitting #{self.id} #{self.name}")
    Bj.submit "./script/runner jobs/add_to_consearch.rb -t #{self.class.name.downcase} -i #{self.id}"
  end
 
  def ft_deindex
    logger.debug("[contentsearch::ftdeindex] removing #{self.id} #{self.name}")
    Bj.submit "./script/runner jobs/remove_from_consearch.rb -t #{self.class.name.downcase} -i #{self.id}"
  end
 
  module ClassMethods
    def ft_search(kw_string)
      clsname = self.name.downcase + "s"
      return self.find_by_sql(["select distinct #{clsname}.id, lots of stuff i deleted here, MATCH(content) against (?) as relevance FROM #{clsname},consearches WHERE consearches.ftable_id = #{clsname}.id and consearches.ftable_type='#{self.name}' and match(content) against (?) order by relevance limit 6",kw_string,kw_string])
    end
  end
end

This example is written in Ruby (on Rails), and the first part is just a convention for putting class methods into a ruby class. How Ruby (and smalltalk and similar languages) handle methods is a fascinating but different discussion but essentially it’s a metaprogramming party and everyone’s invited.

Ruby makes this relatively simple to add as a module to pretty much any class. The reason that ft_index and ft_deindex run in a background process is because taking a document in or out of a fulltext indexed mysql database is way slower than you would want to present to the user in an interactive process. This is common in web applications and is part of why you see things like “your [whatever] may not appear in searches right away” from a lot of applications. If you leave them to run on their own they’re fast enough but generally would make the user unhappy.

But basically, what’s going on here is that there’s two separate tables (and different table types in mysql — one of which does fulltext searching and the other of which has ACID properties.) By joining these two tables together, you can search against the content tables and get results back from the main table that stores domain objects. This is probably the simplest version of federating two different search types together. It works pretty smoothly and this sort of thing is in a number of different products.

(And for rails people, the relevant string in the model classes for this is has_one :consearch, :as => :ftable)

But this is obviously trivially simple: the objects in the content search table are representations of the objects in the main table, and there are entirely separate semantics between the two tables (and unfortunately i deleted the examples using both the main and consearch table, but it’s a join and you get the idea.) One of the tables does ‘field operator value’ type searching (ie: relational) and the other is the kind referred to these days as ‘google searching.’

Things get progressively more difficult when one of these things aren’t true — that there isn’t a store that has the single unified version of the document or that the semantics are related but not either identical or entirely different. For example, if I’m searching two different instantiations of my own product, it’s fairly easy — all the fields mean the same thing between the two different databases.

If the products differ by schema or meaning of the schema, you have to make a (semantic) translation between the two to make the search work, and also you have to make some sort of translation on the search results to have the results displayed to the user in a way that makes sense. This might be as simple as ‘one repository has names and one things have titles’ or it might be more complex (names versus ids, names in particular formats, URLs versus descriptive strings, date formats that give seconds versus those that are accurate to the day, etc…)

It’s when you start combining these sorts of things that stuff starts getting more complex. (This is also leaving aside the issue that the protocols to access all of this information is different (although these days more and more of this becomes an adventure in XML parsing and not DLL hell.) Let’s take a simple example, sorting.

Say I have three different datastores Repo1 – Repo3, and they both return objects with titles on them, and I’m sorting the titles:

Repo1: [Alpha, Bravo, Charlie, Delta, Echo, Foxtrot ]
Repo2: [Able, Baker, Charlie, Dog, Easy, Fox]
Repo3: [Alligator, Crocodile, Pterosaur]

It’s fairly easy to implement this sort, there are a few small issues (like paging results versus the page sizes of the underlying repositories, but regardless alphabetic sorts are well-understood in most locales.

However, if you’re searching by something more like ‘relevance‘, you get back a number associated with each result (so the document that had the ‘Alpha’ before might have a score of ’0.91′). It’s simple to order numbers as well, but how do you tell that a number in one datastore corresponds to a number in another? For one thing, those numbers are calculated (mostly) with regards to the particular collection of documents on a given datastore and for another, one repository may just tend to return a higher number for documents that are theoretically as relevant (because there isn’t any agreement about what 0.91 means, it’s just what a function returns.)

So those two things are where it starts to get more complex and needing actual customization and specialization.

In conclusion, this is way too (f) long for the blog, but I was typing it up to explain things that I was talking about yesterday anyway. HTH. Feel free to comment, but if you’re the person I’m proximately writing this for, you should probably send email.

Tags: , , , , , , , , ,

So, for the last while I’ve been working on celiaq.com. It’s a social network for people with Celiac disease and other forms of Gluten Intolerance. It’s designed around the resources that that community has trouble getting reliable information about on the internet, and I think that it’s coming along pretty well.

Right now, it’s looking like that will be done and in a somewhat stable state by 7/15. It’s based on rails and hosted at slicehost right now, although I suspect that it will be moving to Amazon EC2, CloudFront and S3 as it scales to make things easier. It’s a rails/mysql application for the most past, although it would probably run on other db backends.

It’s been an interesting time taking this entire application from vision to deployment, and it’s been a good time. Currently it’s in a beta state, and is soft launched to let interested people enter resources and test the system.

Tags: , , , ,

« Older entries