Reputation: 521
I am getting errors while doing an AJAX call with remote: true
with locals. Here's the error:
ActionView::Template::Error (undefined local variable or method `f' for #<#<Class:0x94db890>:0x9ab41d0>):
Here is my code below:
new.html.erb
<%= form_for(@author) do |f| %>
<div class="field">
<%= f.label :name %><br>
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :age %><br>
<%= f.number_field :age %>
</div>
<%= link_to "Add Books" , remote: true %>
<div id = "add_book"></div>
<%= f.submit %>
Controller
def new
@author = Author.new
@books = @author.books.build
respond_to do |format|
format.html
format.js
end
end
new.js.erb
$("#add_book").append(" <%= escape_javascript(render partial: 'addbook', :locals => { :f => f }) %> ");
Upvotes: 0
Views: 60
Reputation: 3610
You are calling the new action of your controller using remote: true (an AJAX call). This will result in new.js.erb being rendered to be sent back as the response - the new.html.erb will not be processed.
Within new.js.erb you have:
$("#add_book").append(" <%= escape_javascript(render partial: 'addbook', :locals => { :f => f }) %> ");
Meaning it is attempting to render the addbook partial and set up a local variable for it, to be referenced in the partial as f
, and assigning it the value (local to new.js.erb) f
.
new.js.erb has not declared the local var f
and thus your error.
To assist more we would need to know what the intention of this variable is - in what way does _addbook.html.erb require it?
Upvotes: 3
Reputation: 27747
So... the way that an erb template works is this:
Rails generates a page, in your example, this would be new
by going through the new
action in the controller and gathering up all the variables (eg author
and books
).
Then it gets the right template for the action. In the case when you first open up the new
page you get the form... right? That comes from the new.html.erb
template.
So rails reads through the template and runs the ruby code... replacing it with appropriate html. Then it sends the html to the browser.
By the time it's sent it to the browser, there is no longer any ruby code... just html, because the browser doesn't understand ruby, just html - so that's all that gets sent.
Now... the browser has an html form, that contains some js - this would be the add books
link - it's html, that calls some js that sends a request to your rails app.
The rails app then goes through the new
action, gathering the variables again, but this time, it doesn't render the html template... because it got called by js. So it grabs the js
template instead.
At this point rails knows nothing about the html template. Anything that was in the html template is long gone - sent away to the browser. All it knows about is what is in the js
template. It tries to run the ruby code in the template... and it's asking for f
... and f
doesn't exist in your js template... so it gets confused and tells you it doesn't know about this f
thing.
It doesn't matter that at some point in the past it rendered a form called f
, because that belonged to a way distant past request that no longer exists. The browser doesn't tell rails about f
because it never knew about it (that was part of the ruby, not the html that is all that the browser ever saw). So... there is no f
. ;)
In this case - I am not sure you need to pass f
in as a local variable at all. If you are rendering the template that contains the form... then you don't need to pass in a form because it will already be rendering the form. Try just rendering the partial without passing in locals, and see what happens... if you get a bug, we can then work on that.
Upvotes: 1