Model.save() bug

alloy model의 adapter에 idAttribute를 특정 필드로 지정해 놓으면
모델이 생성된 곳에서 .save()가 호출되지 않았을 때 동작하지 않네요.

알로이 버전 1.1.2 입니다


Facebook Group's likes and commnets
ByungDae Sohn(05-21 13:54) : 이해가 잘 안되네요.. 저는 딱히 idAttribute를 지정해서 쓰지 않지만, .save() 호출 잘 하고 있답니다~^^
Daehyeon Shin(05-22 10:03) : ByungDae Sohn 아 네, idAttribute를 지정해서 쓸 때 발생하는 버그에요.
JongEun Lee(05-23 09:47) : 신대현 그냥 궁금해서 그러는데 해당하는 부분의 코드를 볼수 있을까? 모델 생성했던 함수안에서되고 밖에서 안된다는게 신기해서^^. 함수안에서만 접근할 수 변수를 사용한다거나 아니면 모델들을 생성하는 반복문 안에서 하나의 변수를 모두 같이 쓰면서 저장이 한쪽으로만 되는게 아닌가 하는 생각도 들고 말야~ 대현이가 서울이 있다면 티타임때 한번 같이 볼텐데.ㅋㅋ
exports.definition = {
config: {
    columns: {
        // twitter column
        "id_str":"TEXT",
        "name":"TEXT",
        "screen_name":"TEXT",
        "profile_image_url_https":"TEXT",
        "profile_background_image_url": "TEXT",

        // twitter token for login          
        "access_token":"TEXT",
        "access_token_secret":"TEXT",

        // for ACS
        "id_str_acs": "TEXT",
        // "session_id_acs": "TEXT",

        // for yotoo
        "active":"INTEGER",
        "status_active_tab_index":"INTEGER"
    },
    adapter: {
        // idAttribute: "id_str", // 64bit.. but TEXT
        type: "sql",
        collection_name: "account"
    }
},      

extendModel: function(Model) {      
    _.extend(Model.prototype, {
        // extended functions go here
        testFunction: function (attrs){
            Ti.API.info("testFunc: "+ this.get('name'));    // it works!
            for (var key in attrs) {
                var value = attrs[key];
                Ti.API.info("testFunction: "+ value);
            }
        },
        createCollection: function(typeOfCollection){
            var collection = Alloy.createCollection(typeOfCollection);
            collection.twitterApi = this.twitterApi;
            return collection;
        },
        createModel: function(typeOfModel){
            var model = Alloy.createModel(typeOfModel);
            model.twitterApi = this.twitterApi;
            return model;
        }
    }); // end extend

    return Model;
},


extendCollection: function(Collection) {        
    _.extend(Collection.prototype, {
        // extended functions go here

        changeCurrentAccount: function(currentAccount){
            Ti.API.info("[account.js] will change to " + currentAccount.get('name'));

            var isInCollection = false;
            Alloy.Globals.accounts.map(function(account){
                if(account.get('active')){
                    account.set('active', false);
                    account.save();
                }
                if(account === currentAccount){
                    Ti.API.info(currentAccount.get('name') +" is in Collection");
                    isInCollection = true;
                }
            });
            if( !isInCollection ){
                Ti.API.info(currentAccount.get('name')+" will added in Collection");
                Alloy.Globals.accounts.add(currentAccount);
            }
            currentAccount.set('active', true);
                            ** 3. 문제가 되는 곳 입니다 **
            currentAccount.save();

        },
        deleteAccount: function (account){
            Ti.API.debug("before delete: " + Alloy.Globals.accounts.length);
            var currentAccountDeleted = account.get('active');

            Alloy.Globals.accounts.remove(account);
            account.destroy();

            if( currentAccountDeleted && Alloy.Globals.accounts.length > 0){
                Alloy.Globals.accounts.changeCurrentAccount( Alloy.Globals.accounts.at(0) );
            }

            Ti.API.debug("after delete: " + Alloy.Globals.accounts.length);
        },
        addNewAccount: function (callback){
                            ** 1. 이곳에서 모델을 생성합니다**
            var newAccount = Alloy.createModel('account');
            var twitterAdapter = require('twitter');
            ////// var twitterAPI = new TwitterAdapter.Twitter(TwitterAdapter.tokens);
            var twitterApi = twitterAdapter.create();

            // log in via webView
            twitterApi.authorize({
                'onSuccess': function(){
                    // Ti.API.debug("authorize success");
                    // after log in.
                    newAccount.set({
                        'access_token': twitterApi.getAccessTokenKey(),
                        'access_token_secret': twitterApi.getAccessTokenSecret()
                    });

                    // newAccount.set('active', true);
                    newAccount.set('status_active_tab', 0);
                    newAccount.twitterApi = twitterApi;
                    Ti.API.debug("[account.js] accessTokenKey: " + newAccount.get('access_token'));
                    Ti.API.debug("[account.js] accessTokenSecret: " + newAccount.get('access_token_secret'));
                    /////var user = Alloy.createModel('User');
                    /////user.ownerAccount = newAccount;
                    var user = newAccount.createModel('user');

                    user.fetchFromServer({
                        'purpose': 'profile',
                        'params': {},
                        'onSuccess': function(){
                            newAccount.set({
                                'id_str': user.get('id_str'),
                                'name': user.get('name'),
                                'screen_name': user.get('screen_name'),
                                'profile_image_url_https': user.get('profile_image_url_https').replace(/_normal/g, '_bigger'),
                                'profile_background_image_url': user.get('profile_background_image_url')
                            });
                            Ti.API.info("[account.js] name: " + newAccount.get('name'));


                            // save new account to persistence store
                                                            ** 여기서의 .save()는 idAttribute의 지정과 관계없이 잘 동작 합니다 **
                            newAccount.save(); // must call after callback
                            Ti.API.info("[account.js] new account saved");

                                                             ** 2. 이곳에서 생성된 모델을 반환 하구요 **
                            callback(newAccount);
                        },
                        'onFailure': function(){
                            Ti.API.info("[account.js] user.fetchFromServer failure")
                        }
                    }); // user.getUser()

                },
                'onFailure': function(){
                    Ti.API.debug("[account.js] fail to add account");
                }
            }); // twitterAPI.authorize()
        }   // addNewAccount
    }); // end extend

    return Collection;
}

}

addAccount 를 통해 얻은 모델을 사용하다가 changeCurrentAccount 에게 모델을 넘겼을때 .save() 가 동작 하지 않아요.

accounts.map(function(account){
var row = Alloy.createController('accountRow', {
    "account" : account
}).getView();

row.addEventListener(‘click’, function(e){
$.accountsWindow.close();
if( account !== ownerAccount ){
// change current account
accounts.changeCurrentAccount( account );
}
});

$.accountsTable.appendRow(row);

});

이건 뷰 에서 모델을 사용 하는 부분인데요, 모델 아뎁터의 idAttribute 지정하는 라인을 주석처리하면 잘 작동 합니다

대충 말해서 죄송해요!
모델을 생성 했던 함수 안이나 클로저 안에서는 .save()가 잘 동작 하는데요,
그 외의 곳, 모델을 인자로 전달하거나 아무튼 스코프가 다른 위치에서 .save()를 호출하니까 에러 없이 조용히 sqlite에 저장되지 않더라구요.

아 그런데 버그인것이 리포트 되어 있어 더 이상의 버그 발생 조건을 확인 하지 않았어요.
저 조건이 아니라 다른 조건에서 버그가 발동될 수도 있어요.

말이 좀 길어졌는데 아무튼 확실한건 idAttribute를 지정했을때 .save()가 동작하지 않을수도 있으니까
문제가 생겼을때 이쪽을 한번 의심해 보시면 시간절약 하실 수 있으실것 같아서요.

저는 트위터 어카운트의 아이디를 idAttribute로 지정했는데요, 이게 32비트로 저장 할 수 없는 크기의 정수라서 그냥 TEXT로 지정했었거든요.
INTEGER 필드를 idAttribute로 지정하면 문제가 없을 수도 있어요.

대현아 어떤 경우인지 자세히 얘기해줄수 있어? 잘이해 안되서 ^^.

모델이 생성된 곳에서 .save()가 호출되지 않았을 때 동작하지 않네요.

특히 이부분^^
부탁해.

와.. 업데이트된 플랫폼의 버그는 정말 무서운 거군요..