web-dev-qa-db-fra.com

Problèmes de conservation d'un objet dans un tableau, Ruby issues and Rails issues

J'essaie d'ajouter un objet à mon tableau, mais le tableau semble toujours se réinitialiser, au lieu de l'ajouter. Qu'est-ce que je fais mal? Je pense que cela a à voir avec if(defined? libraryshelf) then, ce que j'essaie de faire ici est de découvrir que le tableau existe ou non (si c'est le premier ajout ou non) ..

def add_book
  @listofbooks ||= Array.new
  @listofbooks.Push(params[:booktitle])
  @listofbooks
  respond_to do |format|
    format.html { redirect_to(:back) }
    format.js
  end
end

mon fichier add_book.js.erb

alert('<%= @listofbooks %>');

@listofbooks ne montre que le titre du livre que j'ai ajouté en dernier ..

23
thedeepfield

TL; DR: Les contrôleurs sont apatrides, ils ne voient que la requête entrante. Pour qu'une liste survive à la demande actuelle, vous devez la conserver dans la session ou dans la base de données, en fonction de la durée de vie et d'autres considérations.

Il y a d'autres problèmes ...

Ne pas utiliser defined? pour cela, en fait, n'utilisez pas defined? pour rien. Il n'a pas beaucoup d'utilisations légitimes au niveau de l'application. Dans ce cas, libraryshelf est une variable locale, et à sa première référence dans la méthode, elle ne sera pas toujours définie.

Opérez directement sur @listofbooks et vérifiez simplement @listofbooks or @listofbooks.nil?.

Voici quelques versions qui fonctionnent (je pense) ...

def add_book name
  @listofbooks = [] unless @listofbooks
  @listofbooks << name
end

def add_book name
  @listofbooks ||= []
  @listofbooks << name
end

def add_book name
  @listofbooks = @listofbooks.to_a.Push name # yes, works even if @listofbooks.nil?
end

Aha, votre publication révisée est meilleure ... comme indiqué dans TL; DR: parce que Rails recrée les objets de contrôleur à chaque demande, vous devrez persister tout ce que vous voulez la prochaine fois dans votre session ou base de données.

Le message d'origine nous a dupés en aussi clobbering @listofbooks à chaque fois dans la méthode, nous avons donc pensé que c'était vraiment une question Ruby.

34
DigitalRoss

puisque vous êtes dans une fonction libraryshelf ne sera jamais défini comme une variable locale. Et je suppose que vous utilisez Ruby 1.8.7 donc vous créez un nouveau tableau dans une portée (que vous ne devriez pas pouvoir voir) et l'assignez à @listofbooks

Je suggère

def add_book
    @listofbooks ||= Array.new
    @listofbooks.Push(name)
    @listofbooks # return the entire list, not the last thing pushed
end

Modifier pour refléter la question mise à jour

Il s'agit d'un problème avec le cycle de vie du contrôleur. Pour chaque demande, un nouvel objet contrôleur est instancié afin que toutes les @variables soient effacées entre les demandes. Vous devrez stocker vos variables par quelque chose comme session[:booklist] = @booklist, puis récupérez-le pour la prochaine demande.

6
EnabrenTane

En regardant le code, il semble que la logique écrite diffère de la description de ce que vous voulez faire. Voici ce que je vois votre code dit:

# Create an Empty Array, assign it to @listofbooks
@listofbooks ||= Array.new

# Add the name of a book from a request parameter
@listofbooks.Push("Agile Development with Rails")

# At this point @listofbooks only contains 1 element; we started with 
# an empty array and added 1 element through the request parameter

Cependant, il semble que vous souhaitiez effectuer les opérations suivantes:

def add_book
   # Simply Push the new book title on the array of old books
   @listofbooks << params[:booktitle] 
end
1
rynmrtn