23

I'm trying to add an object to my array, however the array seems to always reset, instead of adding. What am I doing wrong? I think it has to do with if(defined? libraryshelf) then, What I'm trying to do here is find out of the array exists or not (if this is the first add or not)..

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

my add_book.js.erb file

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

@listofbooks only shows the title of the book I last added..

2
  • Have you checked Ruby API Array class? (ruby-doc.org/core/classes/Array.html#M000225). You can use << -method. Commented Jan 29, 2011 at 6:36
  • yes I did. I'm sorta new to rails and its all kind of confusing to me... Commented Jan 29, 2011 at 7:19

3 Answers 3

34

TL;DR: The controller's are stateless, they just see the incoming request. To have a list outlive the current request, you need to persist the list in either the session or in the database, depending on how long you want it to live and other considerations.

There are some other issues...

Don't used defined? for that, in fact, don't use defined? for anything. It doesn't have many legit application-level uses. In this case, libraryshelf is a local variable, and on its first reference in the method it will always not be defined.

Operate directly on @listofbooks and just check @listofbooks or @listofbooks.nil?.

Here are a few working (I think) versions...

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, your revised post is better ... as noted in TL;DR: because Rails recreates controller objects on each request, you will need to persist anything you want next time around in your session or database.

The original post kind of fooled us by also clobbering @listofbooks every time through the method, so we thought it was really a ruby question.

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks for your reply, I tried these but I still only got one result showing. I've updated my code to show you what I've added~
OIC -- Rails creates your controller object all over again with each http request. You have to persist things in a database if you want to see them the next time around. You kind of fooled us by also clobbering @listofbooks every time through the original method.
6

since you're in a function libraryshelf will never be defined as a local variable. And I'm guessing you are using Ruby 1.8.7 so then you are making a new array in a scope (that you shouldn't be able to see ) and assigning that to @listofbooks

I suggest

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

Edit to reflect updated question

This is a problem with the life cycle of the controller. For each request a new controller object is instantiated so any @variables are cleared between requests. You will need to store your variables by something like session[:booklist] = @booklist, then retrieve it for the next request.

7 Comments

Why Array.new instead of []?
@Ryan Bigg Coding style at former employer. Aren't they syntax equivalent for empty arrays?
Is it a good idea to return the list itself? That would allow a caller to mutate it as they please…
@Paul Fisher, That is a good point, and without knowing more about where the code snippet is, or how it fits, it is hard to say. I thought part of the problem might be his view calls this method and only gets the one item and not the array. Thus the comment.
thanks for your reply, however I'm still only showing the last result... I've edited my code to reflect the changes I've made.
|
1

Looking at the code, it seems the logic written differs from the description of what you want to happen. This is what I see your code is saying:

# 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

However, it sounds like you want to do the following:

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

1 Comment

thanks for explaining whats going on~ but I think my issue is something deeper, I submitted another question - stackoverflow.com/questions/4839409/…

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.