开发者

User attribute will not save

My User model has an attribute called "points" and when I try to update it in another model controller (decrementing points), the attribute will not save (even after adding it to attr_accessible).

The method in my Venture Controller code:

def upvote
@venture = Venture.find(params[:id])
if current_user.points < UPVOTE_AMOUNT
  flash[:error] = "Not enough points!"
else
  flash[:success] = "Vote submitted!"
  current_user.vote_for(@venture)
  decremented = current_user.points - UPVOTE_AMOUNT
  current_user.points = decremented
  current_user.save
  redirect_to :back
end

I have even tried using the update_attributes method, but to no avail.

I added a quick little test with flash to see if it was saving:

if current_user.save
    flash[:success] = "Yay"
else
    flash[:error] = "No"
end 

and the error was returned.

current_开发者_JAVA技巧user comes from my Sessions helper:

def current_user
   @current_user ||= user_from_remember_token
end

Thanks ahead of time.

My User model:

class User < ActiveRecord::Base
attr_accessor :password, :points
attr_accessible :name, :email, :password, :password_confirmation, :points

STARTING_POINTS = 50

acts_as_voter
has_karma :ventures

has_many :ventures, :dependent => :destroy

email_regex = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i

validates :name, :presence => true,
                 :length   => { :maximum => 50 }
validates :email, :presence => true,
          :format => { :with => email_regex },
          :uniqueness => { :case_sensitive => false }
validates :password, :presence     => true,
                     :confirmation => true,
                     :length       => { :within => 6..40 }

before_save :encrypt_password
after_initialize :initialize_points

def has_password?(submitted_password)
  password_digest == encrypt(submitted_password)
end

def self.authenticate(email, submitted_password)
  user = find_by_email(email)
  return nil  if user.nil?
  return user if user.has_password?(submitted_password)
end

def self.authenticate_with_salt(id, cookie_salt)
  user = find_by_id(id)
  (user && user.salt == cookie_salt) ? user : nil
end

private

def initialize_points
  self.points = STARTING_POINTS
end  

def encrypt_password
  self.salt = make_salt if new_record?
  self.password_digest = encrypt(password)
end

def encrypt(string)
  secure_hash("#{salt}--#{string}")
end

def make_salt
  secure_hash("#{Time.now.utc}--#{password}")
end

def secure_hash(string)
  Digest::SHA2.hexdigest(string)
end
end

This is what I get after printing <%= debug current_user %>

--- !ruby/object:User 
attributes: 
id: 1
name: Test User
email: a@s.com
created_at: 2011-08-27 21:03:01.391918
updated_at: 2011-08-27 21:03:01.418370
password_digest: 40d5ed415df384adaa5182a5fe59964625f9e65a688bb3cc9e30b4eef2a0614b
salt: ac7a332f5d63bc6ad0f61ceacb66bc154e1cad1164fcaed6189d8cea2b55ffe4
admin: t
points: 50
longitude_user: 
latitude_user: 
attributes_cache: {}

changed_attributes: {}

destroyed: false
errors: !omap []

marked_for_destruction: false
new_record: false
points: 50
previously_changed: {}

readonly: false


You are requiring the user's password to be present any time the user is saved. When the upvote is submitting, the password is not present, therefor validation is not passing.


This would suggest some kind of validation failed. An easy way to circumvent this, is to use update_attribute. This will update a single attribute and save without running the validations.

So instead write

current_user.update_attribute :points, current_user.points - UPVOTE_AMOUNT

This should work.

This does not solve the problem why saving an existing user could fail, so you still need to check your validations and before_save actions.

Hope this helps.

Ha. Indeed. The update_attribute does skip validations, but not the before_save. So, if the before_save is the problem, you only want to trigger if the password has changed, so you could do something like

def encrypt_password
  self.salt = make_salt if new_record?      
  self.password_digest = encrypt(password) if self.password_changed?
end

But this would only work if password is an actual attribute of your model, which seems unlikely. Why would you store the hash (for safety reasons) and the password in cleartext. So ... I guess you only have a password_digest field, and then it should become something like:

def encrypt_password
  self.salt = make_salt if new_record?      
  self.password_digest = encrypt(password) if password.present?
end

Only if a password was given, try to recreate the digest.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜