views:

86

answers:

1

Hey guys here is my code (roughly):

books.html.erb

<% @books.each do |book| %>
    <% @bookid = book.id %>
    <div id="enter_stuff">
    <%= render "input", :bookid => @bookid  %>
    </div>
<%end%>

_input.html.erb

<% @book = Book.find_by_id(@bookid) %>

<strong>your book is: <%=h @book.name %></strong>

create.rjs

page.replace_html :enter_stuff, :partial => 'input', :object => @bookid

The problem here is that only create.js doesn't seem to work (though, if instead of passing the partial I passed "..." it does work, so I know its that there are instance variables in the partial that aren't being reset. Any ideas?)

So the final question, is how do I pass an instance variable to a partial through the create.rjs file?

p.s. I know I will have duplicate div IDs, I'm not worrying about that for now though.

Best, Elliot

A: 

Passing a variable to a partial the way you do should work fine. You haven't shown how your controller code looks, but I'm guessing that you haven't defined @bookid in the create method in your controller. The method should look something like this:

# books_controller.rb
def create
  @book = Book.create(params[:book])
  @bookid = @book.id
end

However, while this solution will probably solve your immediate problem, there is some room for further improvements. There are a few other issues with your code:

  • By passing the book id instead of Book instances to the partial, you need to fetch each book from the database again, even though all books are available in the @books array. By redesigning your partial to use Books instead of their IDs you can avoid unnecessary database access.

  • Inside the partial you're referring to the book (ID) using an instance variable instead of the object passed to the partial. While this works, it's less robust since the instance variable is shared with the controller and the surrounding view code. If you reuse the partial in other contexts where @bookid refers to something else, you might end with variable name collisions. If you rename the partial to _book.html.erb you'll be able to render a book simply using render :partial => @book -- assuming that you've defined book as a resource, Rails will automatically determine the correct partial to use, and make the book available inside the partial as the variable book.

  • Oh, and by the way, get rid of the ID duplication right away. It's great that you're aware of the problem, but it will just cause you trouble later on. By placing a wrapper div around all books you'll be able to get rid of the duplicate IDs and still keep your Ajax updates working.

With the above improvements, the code would look something like this:

app/controllers/books_controller.rb

class BooksController < ApplicationController
  def index
    @books = Book.find(:all)
  end

  def create
    @book = Book.create(params[:book])
  end
end

app/views/books/index.html.erb

<div id="books">
  <%= render :partial => @books %>
</div>

<% remote_form_for Book.new do |f| %>
  New book title: <%= f.text_field :name %>
<% end %>

app/views/books/_book.html.erb

<% div_for book do %>
  <strong>Your book is: <%= h(book.name) %></strong>
<% end %>

create.js.rjs

page.insert_html :bottom, 'books', :partial => @book
Pär Wieslander