私はRuby on Railsに不慣れで、この作業を取得するのに問題があります。基本的には、パスワードの確認ができるユーザー登録ページがあります。Userクラスでは、次の検証があります:
validates :password, confirmation: true
そして、コントローラーには
def create
vals = params[:user]
if(User.exists(vals[:username]))
flash[:warning] = "#{vals[:username]} already exists! Please try a new one. "
else
vals[:create_date] = DateTime.current
user = User.create(vals, :without_protection => :true)
if user==false or user==nil or user==vals
flash[:warning] = "#{vals[:username]} has not been registered successfully. "
else
flash[:notice] = "#{vals[:username]} has been registered. "
end
end
redirect_to users_path
end
問題は、パスワードが確認と一致しても、登録が成功したことを示す通知メッセージが引き続き表示されることです。ご覧のとおり、create
の戻り値をいくつか試しましたが、どれも成功していないようです。パスワードが確認と一致しない場合、作成したばかりのユーザーが表示されないため、検証が機能していると確信しています。また、create!
、検証エラーでWebサイトがクラッシュするのを確認できます。レコードが検証されない場合、create
が何を返すべきかを誰かに教えてもらえますか?
ありがとう。
あなたの質問への答えは、_User.create
_は、成功するとUser
インスタンスを返しますorは失敗します。検証のために失敗した場合、インスタンスは無効になり、エラーが発生します。
_user.valid? # <= returns false
user.errors.count # <= will be > 0
user.errors.blank? # <= will be false
_
したがって、コードは次のように変更されます。
_if user==false or user==nil or user==vals
_
これに:
_if !user.valid?
_
次のパターンも使用できます。
_user.attributes = vals
if user.save
... save succeeded ...
else
... save failed ...
end
_
save
メソッドは、既存のインスタンスで呼び出しているため、ブール値true
またはfalse
を返します。
しかし、他のいくつかの方法で正しい軌道に乗ることができます:
最初:あなたはこれを持っています:
_if User.exists(vals[:username])
_
(私はexits
はUser
モデルにRailsのことではないので、あなたがあなたのモデルに置いた方法だと思います。)コントローラでそのチェックを行う代わりに、モデルに対して別の検証を使用できます。
_class User < ActiveRecord::Base
...
validates :username, unique: true
...
end
_
ユーザーを作成しようとすると、その名前のユーザーがすでに存在する場合、検証に失敗します。
2番目:あなたはこれを持っています:
_vals[:create_date] = DateTime.current
_
これは不要です。 _created_at
_というモデルに列を追加すると、作成日が自動的に保持されます(ActiveRecordによって管理されます)。これとそのパートナー_updated_at
_を次のように移行のモデルに追加できます。
_create_table :users do |t|
...
t.timestamps # <= tells Rails to add created_at and updated_at
end
_
または、すでにusers
テーブルがあるので:
_add_column :users, :created_at, :datetime
add_column :users, :updated_at, :datetime
_
これで、追加のコードを必要とせずに、ユーザーモデルの作成日時と最終更新日時が常に得られます。
3番目:あなたはこれを持っています:
_user = User.create(vals, :without_protection => :true)
_
これを行わないでください。代わりに、これを変更します。
_vals = params[:user]
_
これに:
_vals = params.require(:user).permit(:username, :password, :password_confirmation)
_
そして保護を維持します:
_user = User.create(vals)
_
フォームからpermit()
呼び出しに持ち込む列を追加できます。この種のものを後で修正するのは難しいので、これは非常に重要です。 「いったんあなたが暗い道を進んだら、それは永遠にあなたの運命を支配するでしょう。」
4番目:保存に失敗した場合、表示するユーザーモデルがないため、_user_path
_にリダイレクトしないでください。代わりに、new
フォームを再レンダリングする必要があります。エラーのフラッシュメッセージも必要ありません。 new
フォームがレンダリングされる場合、_@user.errors
_をチェックし、それに応じてエラーメッセージを報告できます。 ActiveRecordエラーオブジェクトのドキュメント を参照してください。
最後に:あなたは、パスワードが正しく確認されても検証が失敗すると述べました。フォームコードを確認しないとわかりませんが、パスワードフィールドがpassword
で、確認フィールドが_password_confirmation
_であることを確認してください。 Railsは、確認のための検証時に、特にこの_*_confirmation
_フィールド値を探します。
それでうまくいかない場合は、フォームコードを投稿してください。修正します。
答えはActiveRecord object
です。公式のソースコードは、オブジェクトが成功または失敗した場合にcreate
がオブジェクトを返すことを示しています。
# File activerecord/lib/active_record/persistence.rb, line 29
def create(attributes = nil, &block)
if attributes.is_a?(Array)
attributes.collect { |attr| create(attr, &block) }
else
object = new(attributes, &block)
object.save
object
end
end
成功か失敗かを判断する方法
本当の答えはpersisted?
:
if user.persisted?
# Success
else
# Failed
end
なぜuser.valid?
を使用しなかったのですか?他のモデルを操作するいくつかのコールバックが失敗した場合、それだけでは不十分な場合があるためです:
class One < ActiveRecord::Base
has_many :twos
after_create :create_twos_after_create
def create_twos_after_create
# Use bang method in callbacks, than it will rollback while create two failed
twos.create!({}) # This will fail because lack of the column `number`
end
end
class Two < ActiveRecord::Base
validates :number, presence: true
end
ここで、One.create
を実行すると失敗し、ログファイルを確認します。2つを作成できなかったため、ロールバックになります。この場合、One.create.valid?
は引き続きtrue
を返しますが、実際には作成に失敗したため、One.create.persisted?
を使用して置き換える必要があります。
注意:コードはRails 5.1。