Je suis nouveau sur Ruby on Rails et j'ai du mal à obtenir ce travail. Fondamentalement, j'ai une page d'inscription d'utilisateur qui a une confirmation de mot de passe. Dans la classe d'utilisateur I avoir la validation suivante:
validates :password, confirmation: true
Et dans le contrôleur, j'ai
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
Le problème est que lorsque le mot de passe correspond à la confirmation, je reçois toujours le message de notification indiquant que l'enregistrement a réussi. Comme vous pouvez le voir, j'ai essayé plusieurs valeurs de retour pour create
mais aucune ne semble réussir. Je suis à peu près sûr que la validation fonctionne car je ne peux pas voir l'utilisateur que je viens de créer si le mot de passe ne correspond pas à la confirmation. De plus, lorsque j'utilise create!
, Je peux voir le site Web se bloquer avec l'erreur de validation. Quelqu'un peut-il m'aider à me dire ce que create
doit retourner lorsque l'enregistrement n'est pas validé?
Merci.
La réponse à votre question est: User.create
Renvoie une instance User
si elle réussit ou échoue. S'il échoue en raison de validations, l'instance sera invalide et comportera des erreurs:
user.valid? # <= returns false
user.errors.count # <= will be > 0
user.errors.blank? # <= will be false
Votre code changerait donc de ceci:
if user==false or user==nil or user==vals
pour ça:
if !user.valid?
Vous pouvez également utiliser ce modèle:
user.attributes = vals
if user.save
... save succeeded ...
else
... save failed ...
end
La méthode save
renvoie un booléen true
ou false
puisque vous l'appelez sur une instance existante.
Mais permet de vous mettre sur la bonne voie de plusieurs autres façons:
Premièrement: vous avez ceci:
if User.exists(vals[:username])
(Je suppose que exits
est une méthode que vous mettez sur votre modèle User
parce que ce n'est pas une chose Rails). Au lieu de faire cette vérification dans votre contrôleur , vous pouvez simplement utiliser une autre validation sur le modèle:
class User < ActiveRecord::Base
...
validates :username, unique: true
...
end
Maintenant, lorsque vous essayez de créer l'utilisateur, la validation échouera si vous en avez déjà un avec ce nom.
Deuxième: Vous avez ceci:
vals[:create_date] = DateTime.current
C'est inutile. Si vous ajoutez une colonne à votre modèle appelée created_at
, Elle contiendra automatiquement la date de création (gérée par ActiveRecord). Vous pouvez ajouter ceci et son partenaire updated_at
À votre modèle dans votre migration comme ceci:
create_table :users do |t|
...
t.timestamps # <= tells Rails to add created_at and updated_at
end
Ou, puisque vous avez déjà une table users
:
add_column :users, :created_at, :datetime
add_column :users, :updated_at, :datetime
Maintenant, vous aurez toujours la date/heure de création et la dernière mise à jour de votre modèle utilisateur sans avoir besoin de code supplémentaire.
Troisièmement: Vous avez ceci:
user = User.create(vals, :without_protection => :true)
Ne fais pas ça. Au lieu de cela, changez ceci:
vals = params[:user]
Pour ça:
vals = params.require(:user).permit(:username, :password, :password_confirmation)
Et puis gardez la protection sur:
user = User.create(vals)
Vous pouvez ajouter toutes les colonnes supplémentaires que vous souhaitez apporter de votre formulaire à l'appel permit()
. C'est très important car il est difficile de réparer ce genre de chose plus tard. "Si une fois que vous descendez le chemin sombre, il dominera à jamais votre destin."
Quatrième: Vous ne devez pas rediriger vers le user_path
Si la sauvegarde a échoué, car il n'y aura pas de modèle utilisateur à afficher. Au lieu de cela, vous devez restituer votre formulaire new
. Vous n'avez également pas besoin de messages flash pour les erreurs. Si le formulaire new
s'affiche, il peut vérifier @user.errors
Et signaler les messages d'erreur en conséquence. Voir la documentation d'objet d'erreur ActiveRecord .
Enfin: Vous mentionnez que votre validation échoue même lorsque votre mot de passe est correctement confirmé. Je ne peux pas dire avec certitude sans voir votre code de formulaire, mais assurez-vous que votre champ de mot de passe s'appelle password
et que le champ de confirmation s'appelle password_confirmation
. Rails recherche cette valeur de champ *_confirmation
Spécifiquement lors de la validation pour confirmation.
Si cela ne le fait pas, postez votre code de formulaire et je réviserai.
La réponse est ActiveRecord object
. Le code source officiel montre que create
retourne l'objet s'il réussit ou échoue:
# 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
Comment juger qu'il réussit ou échoue
La vraie réponse est persisted?
:
if user.persisted?
# Success
else
# Failed
end
Pourquoi n'a pas utilisé user.valid?
pour le faire? Parce que parfois, cela ne suffit pas lorsqu'il y a des rappels qui fonctionnent sur d'autres modèles:
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
Maintenant, nous exécutons One.create
échouera, vérifiez le fichier journal, ce sera un retour en arrière car il n'a pas pu en créer deux. Dans ce cas, One.create.valid?
renvoie toujours true
, mais sa création a échoué, utilisez donc One.create.persisted?
pour le remplacer est nécessaire.
Remarque: Le code est testé dans Rails 5.1.