-
Notifications
You must be signed in to change notification settings - Fork 37
Cookbook
- Differing local/remote property names
- Send-only property
- Retrieve-only property
- Entirely local property
- Don't send any nested properties
- Deep-nest a relationship property
- To-one relationship
- To-many relationship
- Belongs-to relationship
@implementation User
+ (NSString *) remoteModelName
{
return @"subscriber";
}
+ (NSString *) remoteControllerName
{
return @"subscriberz";
}
@end
@interface MyClass : NSRRemoteObject
@property (nonatomic, strong) NSArray *csvArray; //on the server this is a comma-separated string
@end
@implementation MyClass
@synthesize csvArray;
- (id) encodeValueForProperty:(NSString *)property remoteKey:(NSString **)remoteKey
{
//return the array as a comma-separated string to send out to remote
if ([property isEqualToString:@"csvArray"])
return [csvArray componentsJoinedByString:@","];
return [super encodeValueForProperty:property];
}
- (void) decodeRemoteValue:(id)remoteObject forRemoteKey:(NSString *)remoteKey
{
if ([remoteKey isEqualToString:@"csv_array"])
{
//set our array from the "array string"
self.csvArray = [remoteObject componentsSeparatedByString:@","];
}
else
{
[super decodeRemoteValue:remoteObject forRemoteKey:remoteKey];
}
}
@end
@interface MyClass : NSRRemoteObject
@property (nonatomic, strong) NSURL *URL; //on the server this is just a plain string
@end
@implementation MyClass
@synthesize URL;
- (id) encodeValueForProperty:(NSString *)property remoteKey:(NSString **)remoteKey
{
//return the URL as a string to send out to remote
if ([property isEqualToString:@"URL"])
return [URL absoluteString];
return [super encodeValueForProperty:property];
}
- (void) decodeRemoteValue:(id)remoteObject forRemoteKey:(NSString *)remoteKey
{
if ([remoteKey isEqualToString:@"url"])
{
self.URL = [NSURL URLWithString:remoteObject];
}
else
{
[super decodeRemoteValue:remoteObject forRemoteKey:remoteKey];
}
}
@end
@implementation User
@synthesize objcProperty;
- (NSString *) propertyForRemoteKey:(NSString *)remoteKey
{
if ([remoteKey isEqualToString:@"rails_property"])
return @"objcProperty";
return [super propertyForRemoteKey:remoteKey];
}
- (id) encodeValueForProperty:(NSString *)property remoteKey:(NSString **)remoteKey
{
if ([property isEqualToString:@"objcProperty"])
*remoteKey = @"rails_property";
return [super encodeValueForProperty:property remoteKey:remoteKey];
}
@end
Ruby implementation of encodeValueForProperty:remoteKey:
:
def encodeValueForProperty(property, remoteKey:key)
if (property == "objcProperty")
key[0] = "rails_property"
end
super
end
@implementation User
- (NSMutableArray *) remoteProperties
{
NSMutableArray *props = [super remoteProperties];
[props addObject:@"uniqueDeviceID"];
return props;
}
- (id) encodeValueForProperty:(NSString *)property remoteKey:(NSString **)remoteKey
{
if ([property isEqualToString:@"uniqueDeviceID"])
return [[UIDevice currentDevice] uniqueIdentifier];
return [super encodeValueForProperty:property remoteKey:remoteKey];
}
//Ignore it if your server sends it back...
- (void) decodeRemoteValue:(id)remoteObject forRemoteKey:(NSString *)remoteKey
{
if (![remoteKey isEqualToString:@"unique_device_id"])
[super decodeRemoteValue:remoteObject forRemoteKey:remoteKey];
}
@end
@implementation User
@synthesize retrieveOnlyProperty;
- (BOOL) shouldSendProperty:(NSString *)property whenNested:(BOOL)nested
{
if ([property isEqualToString:@"retrieveOnlyProperty"])
return NO;
return [super shouldSendProperty:property whenNested:nested];
}
@end
@implementation User
@synthesize totallyLocal;
- (NSMutableArray *) remoteProperties
{
NSMutableArray *props = [super remoteProperties];
[props removeObject:@"totallyLocal"];
return props;
}
@end
@implementation User
@synthesize retrieveOnlyProperty;
- (BOOL) shouldSendProperty:(NSString *)property whenNested:(BOOL)nested
{
if ([self nestedClassForProperty:property])
return NO;
return [super shouldSendProperty:property whenNested:nested];
}
@end
Deep-nesting refers to sending a nested attribute when the object itself is nested. In other words, let's say a User is being sent. A User has many Posts, and a Post has many Responses. When the User is sent, all of its Posts will be nested as well. However, by default, this is as far as the representation will go - it is only shallow. If you want the posts to also include their nested properties (responses), shouldSendProperty:whenNested:
has to be overridden.
@implementation Post
@synthesize user, responses;
- (Class) nestedClassForProperty:(NSString *)property
{
if ([property isEqualToString:@"responses"])
return [Post class];
return [super nestedClassForProperty:property];
}
- (BOOL) shouldSendProperty:(NSString *)property whenNested:(BOOL)nested
{
if ([property isEqualToString:@"responses"] && nested)
return YES;
return [super shouldSendProperty:property whenNested:nested];
}
@end
The reason nested objects only send shallow representations is to preempt infinite loops that could occur when a two-way relationship exists (User has many Post, so send the Post, which belongs to User, so send the User, so send the Post, so send the User, etc etc).
Nothing needed! If you have a to-one relationship in your class,
@interface Employee : NSRRemoteObject
@property (nonatomic, strong) Boss *boss;
@end
NSRails will automatically assume that an "Employee has one Boss". (It's in the base class implementation of nestedClassForProperty:
to just return the property type if it is an NSRRemoteObject subclass.)
-
If, on your server, this class holds the foreign key (ie, if Employee has
boss_id
on the server and you want to sendboss_id
instead ofboss_attributes
) it requires a method override. See belongs-to. -
Make sure your Rails controller includes
boss
when sending the JSON for Employee:
render :json => @employee.to_json(:include => [:boss])
- And if you want to be able to send Boss attributes when updating your Employee, add this to your model:
class Employee < ActiveRecord::Base
has_one :boss
accepts_nested_attributes_for :boss, :allow_destroy => true
end
@implementation User
@synthesize posts;
- (Class) nestedClassForProperty:(NSString *)property
{
if ([property isEqualToString:@"posts"])
return [Post class];
return [super nestedClassForProperty:property];
}
@end
- Make sure your Rails controller includes
posts
when sending the JSON for User:
render :json => @user.to_json(:include => [:posts])
- And if you want to be able to send Post attributes when updating your User, add this to your model:
class User < ActiveRecord::Base
has_many :posts
accepts_nested_attributes_for :posts, :allow_destroy => true
end
By default, when sending a nested object, NSRails will send the object's dictionary in a key like <property>_attributes
. However, this can't be done if your model is defined on your Rails server as belongs-to (ie, it has a foreign key - <property>_id
). In this case, return YES
for shouldOnlySendIDKeyForNestedObjectProperty:
:
@implementation User
@synthesize group;
- (BOOL) shouldOnlySendIDKeyForNestedObjectProperty:(NSString *)property
{
return [property isEqualToString:"group"];
}
@end
- When sending "group", NSRails will now send only its ID in a
group_id
key instead of its contents in agroup_attributes
key - This allows you to have a real Group object as a property (instead of just a foreign key integer), but still send it as a foreign key
-
Warning: Of course, this means that modifications on the
user.group
object will not be updated to the server when calling[user remoteUpdate:]
since the property will be replaced withgroup_id
. It can be argued that modifications to theuser.group
object should be called with[user.group remoteUpdate:]
anyway.