Found a nasty bug in object mapping with nil values vs missing key paths. Polished login and sign up patterns thoroughly. Login/Logout & sign up are functional again. Now to move through the rest of the app

This commit is contained in:
Blake Watters
2011-01-20 00:14:21 -05:00
parent 723653585b
commit f7553d7ac0
16 changed files with 334 additions and 132 deletions

View File

@@ -20,4 +20,14 @@ extern NSString* const DBRestKitBaseURL;
// TODO: See if we can eliminate or abstract this further
extern NSString* const kObjectCreatedUpdatedOrDestroyedNotificationName;
extern NSString* const kAccessTokenHeaderField;
/**
* Server Environments for conditional compilation
*/
#define DB_ENVIRONMENT_DEVELOPMENT 0
#define DB_ENVIRONMENT_STAGING 1
#define DB_ENVIRONMENT_PRODUCTION 2
// Use Production by default
#ifndef DB_ENVIRONMENT
#define DB_ENVIRONMENT DB_ENVIRONMENT_PRODUCTION
#endif

View File

@@ -8,9 +8,14 @@
#import "DBEnvironment.h"
// TODO: Add conditional compilation!
NSString* const DBRestKitBaseURL = @"http://localhost:3000";
//NSString* const kDBBaseURLString = @"http://discussionboard.heroku.com";
NSString* const kObjectCreatedUpdatedOrDestroyedNotificationName = @"kObjectCreatedUpdatedOrDestroyedNotificationName";
// Base URL
#if DB_ENVIRONMENT == DB_ENVIRONMENT_DEVELOPMENT
NSString* const DBRestKitBaseURL = @"http://localhost:3000";
#elif DB_ENVIRONMENT == DB_ENVIRONMENT_STAGING
// TODO: Need a staging environment...
#elif DB_ENVIRONMENT == DB_ENVIRONMENT_PRODUCTION
NSString* const DBRestKitBaseURL = @"http://discussionboard.heroku.com";
#endif
NSString* const kAccessTokenHeaderField = @"X-USER-ACCESS-TOKEN";
// TODO: Eliminate
NSString* const kObjectCreatedUpdatedOrDestroyedNotificationName = @"kObjectCreatedUpdatedOrDestroyedNotificationName";

View File

@@ -24,17 +24,21 @@
#import "DBPost.h"
#import "DBManagedObjectCache.h"
#import "DBTopicViewController.h"
#import "DBLoginViewController.h"
#import "DBLoginOrSignUpViewController.h"
#import "DBUser.h"
#import "DBPostTableViewController.h"
/**
* The HTTP Header Field we transmit the authentication token obtained
* during login/sign-up back to the server. This token is verified server
* side to establish an authenticated session
*/
static NSString* const kDBAccessTokenHTTPHeaderField = @"X-USER-ACCESS-TOKEN";
@implementation DiscussionBoardAppDelegate
@synthesize window;
#pragma mark -
#pragma mark Application lifecycle
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Initialize object manager
RKObjectManager* objectManager = [RKObjectManager objectManagerWithBaseURL:DBRestKitBaseURL];
@@ -44,7 +48,9 @@
[RKRequestTTModel setDefaultRefreshRate:1];
// Do not overwrite properties that are missing in the payload to nil.
objectManager.mapper.missingElementMappingPolicy = RKIgnoreMissingElementMappingPolicy;
// TODO: Fix! There is a bug where elements that are in the payload
// objectManager.mapper.missingElementMappingPolicy = RKIgnoreMissingElementMappingPolicy;
objectManager.mapper.missingElementMappingPolicy = RKSetNilForMissingElementMappingPolicy;
// Initialize object store
objectManager.objectStore = [[[RKManagedObjectStore alloc] initWithStoreFilename:@"DiscussionBoard.sqlite"] autorelease];
@@ -56,18 +62,18 @@
[mapper registerClass:[DBPost class] forElementNamed:@"post"];
// Set Up Router
// TODO: Switch to Rails Router
RKDynamicRouter* router = [[[RKDynamicRouter alloc] init] autorelease];
// RKRailsRouter* router = [[[RKRailsRouter alloc] init] autorelease];
// TODO: Comment me!
RKRailsRouter* router = [[[RKRailsRouter alloc] init] autorelease];
[router setModelName:@"user" forClass:[DBUser class]];
[router routeClass:[DBUser class] toResourcePath:@"/signup" forMethod:RKRequestMethodPOST];
[router routeClass:[DBUser class] toResourcePath:@"/login" forMethod:RKRequestMethodPUT];
// [router setModelName:@"topic" forClass:[DBTopic class]];
[router setModelName:@"topic" forClass:[DBTopic class]];
[router routeClass:[DBTopic class] toResourcePath:@"/topics" forMethod:RKRequestMethodPOST];
[router routeClass:[DBTopic class] toResourcePath:@"/topics/(topicID)" forMethod:RKRequestMethodPUT];
[router routeClass:[DBTopic class] toResourcePath:@"/topics/(topicID)" forMethod:RKRequestMethodDELETE];
// [router setModelName:@"post" forClass:[DBPost class]];
[router setModelName:@"post" forClass:[DBPost class]];
[router routeClass:[DBPost class] toResourcePath:@"/topics/(topicID)/posts" forMethod:RKRequestMethodPOST];
[router routeClass:[DBPost class] toResourcePath:@"/topics/(topicID)/posts/(postID)" forMethod:RKRequestMethodPUT];
[router routeClass:[DBPost class] toResourcePath:@"/topics/(topicID)/posts/(postID)" forMethod:RKRequestMethodDELETE];
@@ -82,25 +88,39 @@
[map from:@"db://topics/new" toViewController:[DBTopicViewController class]];
[map from:@"db://posts/(initWithPostID:)" toViewController:[DBPostTableViewController class]];
[map from:@"db://topics/(initWithTopicID:)/posts/new" toViewController:[DBPostTableViewController class]];
[map from:@"db://login" toModalViewController:[DBLoginViewController class]];
[map from:@"db://login" toModalViewController:[DBLoginOrSignUpViewController class]];
[map from:@"*" toViewController:[TTWebController class]];
[[TTURLRequestQueue mainQueue] setMaxContentLength:0]; // Don't limit content length.
[[TTURLRequestQueue mainQueue] setMaxContentLength:0]; // Don't limit content length.
// Register for authentication notifications
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(setAccessTokenHeaderFromAuthenticationNotification:) name:DBUserDidLoginNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(setAccessTokenHeaderFromAuthenticationNotification:) name:DBUserDidLogoutNotification object:nil];
// Initialize authenticated access if we have a logged in current User reference
DBUser* user = [DBUser currentUser];
if ([user isLoggedIn]) {
NSLog(@"Found logged in User record for username '%@' [Access Token: %@]", user.username, user.singleAccessToken);
[objectManager.client setValue:user.singleAccessToken forHTTPHeaderField:kDBAccessTokenHTTPHeaderField];
}
// Fire up the UI!
TTOpenURL(@"db://topics");
[[TTNavigator navigator].window makeKeyAndVisible];
DBUser* user = [DBUser currentUser];
NSLog(@"Token: %@", user.singleAccessToken);
NSLog(@"User: %@", user);
[objectManager.client setValue:[DBUser currentUser].singleAccessToken forHTTPHeaderField:kAccessTokenHeaderField];
return YES;
}
// Watch for login/logout events and set the Access Token HTTP Header
- (void)setAccessTokenHeaderFromAuthenticationNotification:(NSNotification*)notification {
DBUser* user = (DBUser*) [notification object];
RKObjectManager* objectManager = [RKObjectManager sharedManager];
[objectManager.client setValue:user.singleAccessToken forHTTPHeaderField:kDBAccessTokenHTTPHeaderField];
}
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
[window release];
[super dealloc];
}