Атрибут пользователя не сохранит - PullRequest
1 голос
/ 28 августа 2011

Моя модель пользователя имеет атрибут, называемый «точками», и когда я пытаюсь обновить его в другом контроллере модели (уменьшая точки), атрибут не сохраняется (даже после добавления его в attr_accessible).

Метод в моем коде Venture Controller:

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

Я даже пытался использовать метод update_attributes, но безрезультатно.

Я добавил небольшой тест со вспышкой, чтобы проверить, экономит ли он:

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

и ошибка была возвращена.

current_user от моего помощника Sessions:

def current_user
   @current_user ||= user_from_remember_token
end

Спасибо заранее.

Модель "Мой пользователь":

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

Это то, что я получаю после печати <% = 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

Ответы [ 2 ]

2 голосов
/ 28 августа 2011

Требуется, чтобы пароль пользователя присутствовал при каждом сохранении пользователя. Когда upvote отправляется, пароль отсутствует, поэтому проверка не проходит.

1 голос
/ 28 августа 2011

Это предполагает, что какая-то проверка не удалась.Самый простой способ обойти это - использовать update_attribute.Это обновит один атрибут и сохранит без выполнения проверок.

Поэтому вместо этого напишите

current_user.update_attribute :points, current_user.points - UPVOTE_AMOUNT

Это должно работать.

Это не решает проблему, почему сохранениесуществующий пользователь может потерпеть неудачу, поэтому вам все равно нужно проверить свои проверки и before_save действий.

Надеюсь, это поможет.

Ха.В самом деле.update_attribute пропускает проверки, но не before_save.Таким образом, если проблема связана с before_save, вы можете запускать ее только в случае изменения пароля, поэтому вы можете сделать что-то вроде

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

Но это будет работать, только если password является действительным атрибутомвашей модели, которая кажется маловероятной.Зачем хранить хэш (по соображениям безопасности) и пароль в открытом тексте.Итак ... Я думаю, у вас есть только поле password_digest, и тогда оно должно выглядеть примерно так:

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

Только если был задан пароль, попробуйте заново создать дайджест.

...