Saturday, November 23, 2013

Angularjsでcode上でpropertyをrefreshする

AngularJSを使うとHTML上のng-modelを指定したelementとjsコード上で$scope.hogeで指定したプロパティを自動的に同期してくれるのですが、コード上でプロパティを変更しても、そのままでは同期してくれません。

っていうところでいささかはまった話です。

なにやら以下のように書く必要があるようです。




$scope.$apply(function () {
    $scoep.anyProperty = 'hogehoge';
});

$applyの引数には式を文字列としても渡せるみたいです。

Thursday, November 21, 2013

socket.ioを使ってimageをuploadする

画像なんてsocket越しにアップロードするものかわかりませんが。
expressjs + socket.ioでsocketごしに画像をサーバーに送信 > サーバー側でそれを画像として保存後、URLをクライアントに配信 > それをまた画面で受け取って表示するというサンプルを書いて実験してみました。

ポイントとしては
FileReader#readAsDataURLでDataURI形式にした画像を文字列としてサーバーに送る


         var file = input.files[0];
         var name = file.name;

         var reader = new FileReader();
         reader.onloadend = function (e) {
             var data = e.target.result;

             if (!data) {
                 return ;
             }

             socket.emit('upload', { name : name, data : data});
         };

         reader.readAsDataURL(file);


サーバー側で文字列的にbase64でencodeしてある部分を取り出して画像としてファイルに出力
                var imgStructure = img.split(',');
                var base64 = imgStructure[1];

                fs.writeFile(
                    './public/' + name,
                    new Buffer(base64, 'base64'),
                    function (err) {
                        console.log(err);
                    }
                );


その後はクライアント側で関しているイベントにたいして出力した画像のパスを配信
socket.emit('notify', {url : publicUrl});


クライント側で、受け取った画像パスをimgタグに突っ込んで表示
     socket.on('notify', function (data) {
                   console.log(data);
                   $('#image001').attr('src', data.url);

               });


実際に作成したサンプルは下においてあります。
https://github.com/hiroyukimizukami/socketio-image

Tuesday, November 12, 2013

RubyOnRailsとiOSでアプリを作る時にすばらしく便利なNSRails

Rails + iOSという組み合わせは割と多いと思うんだけど。いちいちサーバーとクライントの繋ぎ込みを自前で書くのはつらいなーと思って調べたら、NSRailsという便利なのがあったので試してみた。

https://github.com/dingbat/nsrails

Railsのモデルと対になるものをiOS側で定義しておくとiOSのオブジェクトを操作するだけサーバにデータを永続化したり、データの取得ができる。ざっくりいうとparse.comと非常に使用感が似ている。

導入


導入はcocoapods経由で。Podfileにuse 'NSRails'とかくだけ。
pod 'NSRails'

iOS側でRailsアプリの場所を指定するには、AppDelegateで以下のように指定するだけ。
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    // Override point for customization after application launch.
    
    [NSRConfig defaultConfig].appURL = @"http://localhost:3000";
    
    return YES;
}

Railsアプリ


アプリと適当なオブジェクト+エンドポイント一式を作っておく
rails new nsrails_test_server
rails g scaffold user name:string email:string passwd:string created_at:datetime updated_at:datetime

あと、RailsアプリにCSRF対策用のキーをチェックする設定が入っているので/app/controllers/application_controller.rbのprotect_from_forgeryを:exceptionから:null_sessionに変更し無効とする。

protect_from_forgery with: :null_session


iOSアプリ

Railsのモデルに対応するモデルをクライアントとに定義する。NSRRemoteObjectを継承したクラスを作成。プロパティ名はRails側と合わせておく。


#import "NSRails.h"

@interface JpPluscNSRailsTestUser : NSRRemoteObject

@property (nonatomic, strong) NSString* name;
@property (nonatomic, strong) NSString* email;
@property (nonatomic, strong) NSString* passwd;
@property (nonatomic, strong) NSString* gender;

@end

iOS側のオブジェクトはプレフィックスの都合とかでRailsとあわせられない事が多いと思うので、そういう場合は実装ファイルでremoteModelName, remoteControllerNameを上書きする
+ (NSString *) remoteModelName
{
    return @"user";
}

+ (NSString *) remoteControllerName
{
    return @"users";
}

@end


あとはオブジェクトの作成、永続化、取得等が以下のように簡単にかける。
    //オブジェクト作成、永続化
    user = [[JpPluscNSRailsTestUser alloc] init];
    user.name = self.aName.text;
    user.email = self.aEmail.text;
    user.passwd = self.aPasswd.text;
    
    [user remoteCreateAsync:^(NSError *error) {
        if (error != nil) {
            NSLog(@"%@", error);
        }
    }];

    //取得
    [JpPluscNSRailsTestUser remoteAllAsync:^(NSArray *allRemote, NSError *error) {
        NSMutableArray *indexPaths = [NSMutableArray array];
        NSInteger size = [allRemote count];

        //画面レンダリングなど...        

    }];


実際に書いたコード iOS
Rails