RailsTutorialサンプルアプリ(Twitterのようなアプリケーション)をインストールしましたが、ユーザーdbを更新しようとすると、次のコンソールコードがデータベースを更新しない理由を理解しようとしています。 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
Railsコンソール:
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: "$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('[email protected]') 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-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
あなたのユーザーモデルはおそらく満足されない検証を持っています。あなたはそれらを投稿していないので、あなたの質問を本当に解決することはできません。ライブをより簡単にするために、ユーザーが保存したくない理由をデバッグできます。
実行してみてください
user.errors.full_messages
これにより、何が間違っているのかがわかります。
私はこれが古い投稿であることを知っていますが、これが将来このチュートリアルを経験する人の助けになることを願っています。
受け入れられた答えが示すように、これは検証が満たされていないためです。私もこの問題に遭遇し、別の回避策はuser
オブジェクトでupdate_attribute
メソッドを使用することであることがわかりました。たとえば、name
オブジェクトのuser
フィールドを更新し、仮想password
およびpassword_confirmation
フィールドに触れることなく、データベースに自動的に保存する場合、次を使用します。
user.update_attribute(:name, "larry")
これにより、name
フィールドのみを更新し、save
およびpassword_confirmation
フィールドに触れることなく、データベースに保存します(password
メソッドを呼び出す必要はありません)。
アクティブなレコードモデルインスタンスを保存または検証しようとすると、いくつかの便利なコマンドで何が起こったのかに関する詳細情報を表示できます。
user = User.find(108)
user.name = "Larry"
user.valid? # returns false
user.errors.messages # returns something like {email: "Cant be blank"}
モデルファイルがどのように見えるかわからないが、通常2つの理由のいずれかでロールバックする場合、明らかにエラーが発生しました。 1つ目は、検証に失敗したことです。エラーメッセージがない場合は、おそらくフィルターチェーン内の何かが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を返していたため、保存が取り消されました(私はRailsを初めて使用します)。
ファイルがアップロードされた後にのみ設定できるブール値を設定しようとしていました。
私がやっていたことは次のとおりです。
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
これが将来誰かに役立つ場合-私は同様の問題を抱えていましたが、ロールバックを引き起こしていたのは、データが検証に合格しなかったことです(問題を発見した後に検証が実装されました)。データを手動で修正することで問題が解決しました。