J'ai une instruction de création pour certains modèles, mais elle crée un enregistrement dans une table de jointure, que l'enregistrement existe déjà ou non.
Voici à quoi ressemble mon code:
@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 que cela crée des enregistrements, peu importe quoi. Je voudrais qu’il crée un disque seulement si aucun disque n’existe déjà; si un enregistrement existe, j'aimerais qu'il prenne l'attribut de l'enregistrement trouvé et ajoute ou soustrait 1.
J'ai regardé autour de moi et vu quelque chose appelé find_or_create_by
. Qu'est-ce que cela fait quand il trouve un disque? Je voudrais qu'il prenne l'attribut actuel :score
et ajoute 1.
Est-il possible de trouver ou de créer avec id
? Je ne suis pas sûr de l’attribut que je trouverais, car le modèle que j’examine est un modèle de jointure qui ne contient que id
clés étrangères et l’attribut score.
J'ai essayé
@user.choices.find_or_create_by_user(:user => @user.id, :interest => interest, :score => 4)
mais j'ai
méthode non définie
find_by_user
Que devrais-je faire?
En supposant que le modèle Choice
ait un user_id
(à associer à un utilisateur) et un interest_id
(à associer à un intérêt), quelque chose comme ceci devrait faire l'affaire:
@user = User.find(current_user)
@event = Event.find(params[:id])
@event.interests.each do |interest|
choice = @user.choices.find_or_initialize_by_interest_id(interest.id) do |c|
c.score = 0 # Or whatever you want the initial value to be - 1
end
choice.score += 1
choice.save!
end
Quelques notes:
user_id
dans le find_or_*_by_*
, car vous avez déjà indiqué à Rails de n'extraire que choices
appartenant à @user
.find_or_initialize_by_*
, qui est essentiellement identique à find_or_create_by_*
, la seule différence étant que initialize
ne crée pas réellement l'enregistrement. Ce serait similaire à Model.new
par opposition à Model.create
.c.score = 0
n'est exécuté que si l'enregistrement n'existe pas pas . choice.score += 1
mettra à jour la valeur du score pour l'enregistrement, qu'il existe ou non. Par conséquent, le score par défaut c.score = 0
devrait être la valeur initiale moins un.choice.save!
mettra à jour l'enregistrement (s'il existait déjà) ou créera l'enregistrement initié (s'il ne l'était pas).my_class = ClassName.find_or_initialize_by_name(name)
my_class.update_attributes({
:street_address => self.street_address,
:city_name => self.city_name,
:Zip_code => self.Zip_code
})
find_or_create_by_user_id
sonne mieux
De plus, dans Rails 3 vous pouvez faire:
@user.choices.where(:user => @user.id, :interest => interest, :score => 4).first_or_create
Si vous utilisez Rails 4, je ne pense pas qu'il crée les méthodes du Finder comme auparavant, par conséquent, find_or_create_by_user n'est pas créé pour vous. Au lieu de cela, vous le feriez comme ceci:
@user = User.find(current_user)
@event = Event.find(params[:id])
for interest in @event.interests
@user.choices.find_or_create_by(:interest => interest) do |c|
c.score ||= 0
c.score += 1
end
end
Dans Rails 4 Vous pouvez utiliser find_or_create_by
pour obtenir un objet (s'il n'existe pas, il le créera), puis utiliser update
pour enregistrer ou mettre à jour l'enregistrement. existe, sinon met à jour l'enregistrement.
Par exemple
@edu = current_user.member_edu_basics.find_or_create_by(params.require(:member).permit(:school))
if @edu.update(params.require(:member).permit(:school, :majoy, :started, :ended))