2012-07-06 75 views
1

我有一個基本的身份驗證系統,就像Michael Hartl的Ruby on Rails Tutorial一樣。基本上,記憶令牌存儲在cookie中。我從Railscast#124實施了Ryan Bate的Beta-Invitations,在那裏你可以發送數量有限的邀請。雖然這樣做,我碰到了問題,the current user got logged out after sending an invitation。這是由這個代碼在邀請函模型造成的:ActiveRecord方法遞減!更新其他屬性。這是爲什麼?

invitation.rb

belongs_to :sender, :class_name => 'User' 
[...] 
before_create :decrement_sender_count, :if => :sender 
[...] 
def decrement_sender_count 
    sender.decrement! :invitation_limit 
end 

在日誌中我看到sender.decrement!不僅更新了invitation_limit但reme​​mber_token還有:

UPDATE "users" SET "invitation_limit" = 9982, "remember_token" = 'PYEWo_om0iaMjwltU4iRBg', "updated_at" = '2012-07-06 09:57:43.354922' WHERE "users"."id" = 1 

我發現了一個ugly workaround,但我很想知道真正的問題是什麼。由於我不知道從哪裏開始,我將向您展示來自用戶控制器的更新方法。還有什麼可能是相關的?

users_controller.rb

def update 
    @user = User.find(params[:id]) 
    if @user.update_attributes(params[:user]) 
    flash[:success] = t('success.profile_save') 
    sign_in @user 
    redirect_to @user 
    else 
    flash.now[:error] = t('error.profile_save') 
    render 'edit' 
    end 
end 

回答

2

decrement!電話save這當然火救回調。它看起來像本書指導你做的

before_save :create_remember_token 
def create_remember_token 
    self.remember_token = SecureRandom.urlsafe_base64 
end 

這意味着保存用戶將始終使記憶令牌無效。我認爲這是因爲當用戶更改密碼時,記憶標記也會發生變化,但這意味着顯然會有一些附帶損害。

你可以使用它在本質上確實

update users set counter_name = counter_name - 1 where id =12345 

不運行任何回調decrement_counter。這也避免了一些競賽情況。但是,無論用戶何時更改,更改令牌都會在您不期望的時候更改令牌 - 您可能只想在相關時更改它(可能是憑據已更改)

+0

非常有見地,非常感謝! – 2012-07-06 10:34:39

2

在我看來,你遇到的ActiveRecord的更新方法的一個常見問題:

在看看ActiveRecord的文檔here你可以看到實際執行的遞減!方法:

def decrement!(attribute, by = 1) 
    decrement(attribute, by).update_attribute(attribute, self[attribute]) 
end 

有趣的是這是在自對象稱爲update_attribute - 儘管該方法意味着ActiveRecord的將只更新指定的屬性,它確實更新了自對象的所有髒屬性。

這意味着如果您在任何時候更改了該對象的記憶標記屬性,它將在update_attributes調用期間保存到數據庫。

如果我是對的,那就是問題 - 只要確保在運行時沒有對remember_token屬性進行更改。

以外,你可以考慮使用ActiveRecord's update_column方法將更新對DB一列沒有物體上進行保存方法

+0

啊,是的,謝謝。直接進入那一個。 – 2012-07-06 10:38:20

相關問題