Ruby-on-rails 为什么当我尝试 user.save 时我的 rails 会回滚?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19037733/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why does my rails rollback when I try to user.save?
提问by Venomoustoad
I have installed the RailsTutorial sample app(the twitter like application) and am trying to understand why the following piece of console code does not update the database when I try updating the user db. I am expecting the user information to get updated once I use the user.save. However, this rolls back to unedited data. Is this due to a user based restriction?
我已经安装了 RailsTutorial 示例应用程序(类似 twitter 的应用程序),并试图理解为什么当我尝试更新用户数据库时,以下控制台代码没有更新数据库。我期待用户信息在我使用user.save. 但是,这会回滚到未编辑的数据。这是由于基于用户的限制吗?
Users controller:
用户控制器:
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
Rails console:
导轨控制台:
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: "[email protected]", created_at: "2013-09-26 18:10:12", updated_at: "2013-09-26 18:10:12", password_digest: "a$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('[email protected]') AND "users"."id" != 109) LIMIT 1
(0.1ms) rollback transaction
=> false
User model:
用户模型:
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-z\d\-.]+\.[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
回答by jewilmeer
Your user model probably has validations which are not satisfied. Since you've not posted those I'm unable to really solve your question. To make live easier you can debug why your user isn't willing to save.
您的用户模型可能有不满意的验证。由于您尚未发布这些内容,因此我无法真正解决您的问题。为了让生活更轻松,您可以调试用户不愿意保存的原因。
Try running
尝试跑步
user.errors.full_messages
which should give you a hint what's going wrong.
这应该给你一个提示出了什么问题。
回答by Richard Gieg
I know this is an old post, but hopefully this might help someone going through this tutorial in the future.
我知道这是一篇旧帖子,但希望这可以帮助将来完成本教程的人。
As the accepted answer expresses, this is due to validations which are not being satisfied. I ran into this issue as well and found that another workaround is to use the update_attributemethod on the userobject. For example, if you want to update the namefield of a userobject and have it automatically save to the database, without having to touch the virtual passwordand password_confirmationfields, use the following:
正如接受的答案所表达的那样,这是由于未满足验证。我也遇到了这个问题,发现另一种解决方法是update_attribute在user对象上使用该方法。例如,如果您想更新name一个user对象的字段并让它自动保存到数据库中,而不必触摸虚拟password和password_confirmation字段,请使用以下命令:
user.update_attribute(:name, "larry")
This will update the namefield only and save it to the database (no need to call the savemethod), without having to touch the passwordand password_confirmationfields.
这将name仅更新字段并将其保存到数据库中(无需调用该save方法),而无需触摸password和password_confirmation字段。
回答by Tyrel Richey
After you try to save or validate an active record model instance you can view more information about what happened with a few useful commands.
在您尝试保存或验证活动记录模型实例后,您可以使用一些有用的命令查看有关所发生情况的更多信息。
user = User.find(108)
user.name = "Larry"
user.valid? # returns false
user.errors.messages # returns something like {email: "Cant be blank"}
Obviously I made that error up because I don't know what your model file looks like but if it roles back its for one of two reasons usually. The first is your validations failed. If their are no error messages its probably because something in your filter chain returned false. For example
显然,我犯了这个错误,因为我不知道你的模型文件是什么样子,但如果它通常出于两个原因之一而起作用。首先是您的验证失败。如果它们没有错误消息,则可能是因为过滤器链中的某些内容返回了 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
Hope that helps
希望有帮助
回答by Max Wong
When save rollbacks, use save! instead, and error log will be printed.
当保存回滚时,使用保存!相反,将打印错误日志。
回答by mechanicalfish
Your validations are not passing. You can do:
您的验证未通过。你可以做:
user.errors.full_messages
in the console after the failed save to see why.
保存失败后在控制台中查看原因。
回答by Kyle Falconer
I had this same problem and no errors were being stored. It turned out that my before_savefunction was returning false which resulted in the save being canceled (I guess? I'm new to rails).
我遇到了同样的问题,并且没有存储任何错误。结果是我的before_save函数返回 false 导致保存被取消(我猜?我是 Rails 的新手)。
I was trying to set the value of a boolean which could only be set once a file had been uploaded.
我试图设置一个布尔值,该值只能在上传文件后设置。
Here's what I was doing:
这是我在做什么:
before_save :set_orientation
def set_orientation
# ...do stuff...
self[:is_landscape] = ratio > 1 # stores AND returns the boolean value!!
end
The last line in the function was also an implicit return which I did not mean to do. My solution was to make the return explicitly:
函数中的最后一行也是一个隐式返回,我不是故意这样做的。我的解决方案是明确返回:
before_save :set_orientation
def set_orientation
# ...do stuff...
self[:is_landscape] = ratio > 1 # store the boolean value
return # now return
end
回答by Michael Klump
I had the same issue of the database rolling back my transactions in the console while I was trying to update the admin property on a user. If you are doing the Hartl rails tutorial, the issue is that if you type in user.errors.messages in the console, it will tell you that the password is too short. That is because in the model there is a password validation before it saves and hashes your password into the password_digest.
我在尝试更新用户的 admin 属性时遇到了同样的问题,即数据库在控制台中回滚我的事务。如果你正在做 Hartl rails 教程,问题是如果你在控制台中输入 user.errors.messages,它会告诉你密码太短。那是因为在模型中存在密码验证,然后它将您的密码保存并散列到 password_digest 中。
The work around to this is in the console perform your normal activity like setting user.admin = true, and then when you are done, enter user.password = "foobar", then enter user.password_confirmation = "foobar", and then when you perform user.save it will commit all your changes.
解决这个问题的方法是在控制台中执行您的正常活动,例如设置 user.admin = true,然后在完成后输入 user.password = "foobar",然后输入 user.password_confirmation = "foobar",然后当您执行 user.save 它将提交您的所有更改。
回答by giangmt
Try to update the database:
尝试更新数据库:
rails db:migrate

