为什么当我尝试 user.save 时我的轨道会回滚



我已经安装了 RailsTutorial 示例应用程序(类似 Twitter 的应用程序),并试图理解为什么当我尝试更新用户数据库时,以下控制台代码不会更新数据库。我希望用户信息在使用user.save后得到更新。但是,这会回滚到未编辑的数据。这是由于基于用户的限制吗?

用户控制器:

class UsersController < ApplicationController
#before_filter :signed_in_user, only: [:index, :edit, :update, :destroy, :following, :followers]
# By default before filters apply to all actions
#before_filter :correct_user, only: [:edit, :update]
  def edit
    @user = User.find(params[:id])
  end
  def update
    @user = User.find params[:id]
    respond_to do |format|
    if @user.update_attributes(params[:user])
      flash[:notice] = "Profile updated"
      format.html { redirect_to(@user, :notice => 'User was successfully updated.') }
      format.json { respond_with_bip(@user) }
    else
      format.html { render :action => "edit" }
      format.json { respond_with_bip(@user) }
    end
    end
 end
  private

  def correct_user
    @user = User.find(params[:id])
    redirect_to(root_path) unless current_user?(@user)
  end
  def admin_user
    redirect_to(root_path) unless current_user.admin?
  end

end

导轨控制台:

1.9.3-p392 :001 > user = User.find(109)

User Load (8.2ms)  SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1  [["id", 109]]
 => #<User id: 109, name: "laurie", email: "auriepage@gmail.com", created_at: "2013-09-26 18:10:12", updated_at: "2013-09-26 18:10:12", password_digest: "$2a$10$aXEtun8Z2Deqy2wNxvFRNOjPczKQkYc1vDezP5OduJuF...", remember_token: "YhIUhgFm9iMewxdNOHJ45A", admin: false> 
1.9.3-p392 :002 > user.name = "larry"
 => "larry" 
1.9.3-p392 :003 > user.save
   (0.2ms)  begin transaction
  User Exists (0.6ms)  SELECT 1 AS one FROM "users" WHERE (LOWER("users"."email") = LOWER('auriepage@gmail.com') AND "users"."id" != 109) LIMIT 1
   (0.1ms)  rollback transaction
 => false 

用户型号:

class User < ActiveRecord::Base
# Declaration of public variables   
  attr_accessible :email, :name, :password, :password_confirmation
  has_secure_password
  has_many :microposts, dependent: :destroy
  has_many :relationships, foreign_key: "follower_id", dependent: :destroy
  has_many :followed_users, through: :relationships, source: :followed
  has_many :reverse_relationships, foreign_key: "followed_id", class_name: "Relationship", dependent: :destroy
  has_many :followers, through: :reverse_relationships, source: :follower
  before_save {email.downcase!}
  before_save :create_remember_token
  validates :name, presence: true, length: {maximum: 50}
  VALID_EMAIL_REGEX = /A[w+-.]+@[a-zd-.]+.[a-z]+z/i
  validates :email, presence: true, format: {with: VALID_EMAIL_REGEX}, uniqueness: {case_sensitive: false}
  validates :password, presence: true, length: {minimum: 6}
  validates :password_confirmation, presence: true
  after_validation {self.errors.messages.delete(:password_digest)}
 private
    def create_remember_token
        self.remember_token = SecureRandom.urlsafe_base64
    end
end

您的用户模型可能具有不满足的验证。由于您尚未发布这些内容,因此我无法真正解决您的问题。为了简化生活,您可以调试用户不愿意保存的原因。

尝试跑步

user.errors.full_messages

这应该给你一个提示,出了什么问题。

我知道

这是一篇旧文章,但希望这可能会帮助将来有人学习本教程。

正如接受的答案所表达的那样,这是由于未满足验证。我也遇到了这个问题,发现另一种解决方法是在user对象上使用 update_attribute 方法。例如,如果要更新user对象的name字段并将其自动保存到数据库中,而不必触摸虚拟passwordpassword_confirmation字段,请使用以下命令:

user.update_attribute(:name, "larry")

这将仅更新name字段并将其保存到数据库(无需调用 save 方法),而无需触摸passwordpassword_confirmation字段。

尝试保存或验证活动记录模型实例后,可以使用一些有用的命令查看有关所发生情况的详细信息。

user = User.find(108)
user.name = "Larry"
user.valid? # returns false
user.errors.messages # returns something like {email: "Cant be blank"}

显然,我犯了这个错误,因为我不知道您的模型文件是什么样子的,但是如果它通常出于以下两个原因之一而重新发挥作用。首先是您的验证失败。如果没有错误消息,可能是因为过滤器链中的某些内容返回了 false。例如

class User << ActiveRecord::Base
  before_save :accidentally_return_false
  def accidentally_return_false
    self.some_boolean = (condition == value)
  end
end
user = User.new( params )
user.save # where condition does not equal value
user.valid? # false because of the before save method

希望有帮助

保存回滚时,请使用 save!,然后打印错误日志。

您的验证未通过。你可以做:

user.errors.full_messages

在控制台中保存失败以查看原因。

我遇到了同样的问题,没有存储任何错误。事实证明,我的before_save函数返回 false,导致保存被取消(我猜?我是轨道的新手)。

我试图设置布尔值,该值只能在上传文件后设置。

这是我在做什么:

before_save :set_orientation
def set_orientation
  # ...do stuff...
  self[:is_landscape] = ratio > 1  # stores AND returns the boolean value!!
end

函数中的最后一行也是一个隐式返回,我无意这样做。我的解决方案是明确返回:

before_save :set_orientation
def set_orientation
  # ...do stuff...
  self[:is_landscape] = ratio > 1  # store the boolean value
  return                           # now return
end

当我尝试更新用户的管理员属性时,我遇到了数据库在控制台中回滚事务的相同问题。如果您正在学习 Hartl rails 教程,问题是如果您在控制台中输入 user.errors.messages,它会告诉您密码太短。这是因为在模型中,在保存密码并将其散列到password_digest之前,需要进行密码验证。

解决方法是在控制台中执行您的正常活动,例如设置 user.admin = true,然后在完成后,输入 user.password = "foobar",然后输入 user.password_confirmation = "foobar",然后在执行 user.save 时,它将提交您的所有更改。

尝试更新数据库:

rails db:migrate

最新更新