Dans les Rails, ce qui est la meilleure façon de mettre à jour un enregistrement ou d'en créer une nouvelle si elle n'existe pas?
J'ai une instruction de création de certains modèles, mais c'est la création d'un enregistrement dans une table de jointure, indépendamment de savoir si l'enregistrement existe déjà.
Voici ce que mon code ressemble à ceci:
@user = User.find(current_user)
@event = Event.find(params[:id])
for interest in @event.interests
@user.choices.create(:interest => interest, :score => 4)
end
Le problème est qu'il crée des enregistrements n'importe quoi. Je tiens à créer un enregistrement uniquement si aucun enregistrement n'existe déjà; si un enregistrement n'existe pas, j'aimerais qu'il prenne l'attribut de l'enregistrement trouvé et d'ajouter ou de soustraire 1.
J'ai été en regardant autour ont vu quelque chose qui s'appelle find_or_create_by
. Qu'est-ce quand il trouve un record? Je tiens à prendre le courant :score
attribut et ajouter 1.
Est-il possible de trouver ou de créer par id
? Je ne suis pas sûr de ce que l'attribut je voudrais trouver en, car le modèle que je suis à la recherche d'une jointure modèle qui n'a id
clés étrangères et le score d'attribut.
J'ai essayé
@user.choices.find_or_create_by_user(:user => @user.id, :interest => interest, :score => 4)
mais il a obtenu
méthode non
find_by_user
Que dois-je faire?
- Est current_user déjà une instance de l'Utilisateur modèle? Si oui, vous n'avez pas besoin de re-trouver et pouvez simplement utiliser
current_user
au lieu de@user = ...
.
Vous devez vous connecter pour publier un commentaire.
En supposant que le
Choice
modèle a unuser_id
(à associer avec un utilisateur) et uninterest_id
(à associer avec un intérêt), quelque chose comme cela devrait faire l'affaire:Quelques remarques:
user_id
colonne dans lafind_or_*_by_*
, comme vous l'avez déjà demandé à des Rails à la seule extractionchoices
appartenant à@user
.find_or_initialize_by_*
, qui est essentiellement la même quefind_or_create_by_*
, avec une différence essentielle étant queinitialize
ne crée pas le dossier. Ce serait semblable àModel.new
par opposition àModel.create
.c.score = 0
est exécuté seulement si l'enregistrement n' pas existent.choice.score += 1
permettra de mettre à jour la valeur du score pour l'enregistrement, peu importe si il existe ou pas. Par conséquent, le nombre de points par défautc.score = 0
devrait être la valeur initiale moins un.choice.save!
sera soit mise à jour de la fiche (si elle existe déjà) ou de créer des initiés de la fiche (si elle n'a pas).find_or_create_by_user_id
sonne mieuxAussi, dans Rails 3 que vous pouvez faire:
first_or_create
est préféré dans les Rails 4, en attendantfind_or_intialize_by_xxx(attribute)
est dépréciée en faveur defind_or_intialize_by(xxx:attribute)
Si vous êtes à l'aide de rails 4 je ne pense pas qu'il crée le finder méthodes comme autrefois, de sorte find_or_create_by_user n'est pas créé pour vous. Au lieu de cela, vous auriez du faire comme ceci:
Dans Les Rails 4
Vous pouvez utiliser
find_or_create_by
pour obtenir un objet(s'il n'existe pas,il va créer), puis utilisezupdate
pour enregistrer ou mettre à jour l'enregistrement, la méthode de mise à jour va persister enregistrement si elle n'est pas exister, sinon mettre à jour l'enregistrement.Par exemple