Basic Ruby on Rails AJAX Error - ruby-on-rails

I'm working through Agile Web Development with Rails, Edition 4 with some tweaks (mostly just naming variations), and I've arrived at Iteration F2. In this iteration, you modify the index button with :remote => true, you add format.js to the respond_to section of the controller, and you generate a js.rjs file to execute the AJAX render. Or at least that's my interpretation of it. The goal of these steps is to have a cart (in this case, a team) in the sidebar update using AJAX when adding new line items (in this case, members)
In my case, I'm trying to add members to a team. Her's some code snippets I've added:
index.html.erb:
<%= button_to 'Add to Team', members_path(:player_id => player),
:remote => true %>
members_controller:
def create
#team = current_team
player = Player.find(params[:player_id])
#member = #team.add_player(player.id)
respond_to do |format|
if #member.save
format.html { redirect_to(nba_url) }
format.js
format.xml { render :xml => #member,
:status => :created, :location => #member }
else
format.html { render :action => "new" }
format.xml { render :xml => #member.errors,
:status => :unprocessable_entity }
end
end
end
create.js.rjs:
page.replace_html('team', render(#team))
The page is able to render, and I'm still able to click the button to add members to the team. However, the AJAX isn't working. When I reload, I can still see that the members have been added in the sidebar. All of the other team functionality remains, as I'm able to empty the team and add whichever members I wish. When I check the server log, I find the following error:
Error:
ActionView::Template::Error (undefined local variable or method `page' for #<
#<Class:0x413e1b8>:0x413cb20>):
1: page.replace_html('team', render(#team))
app/views/members/create.js.rjs:1:in `block in _app_views_members_create_js_rj
s___908569197_34199712_807066544'
app/views/members/create.js.rjs:1:in `_app_views_members_create_js_rjs___90856
9197_34199712_807066544'
app/controllers/members_controller.rb:47:in `create'
Based on this it seems like it has found the create.js.rjs but is having trouble interpreting it. I'm not sure what the weird symbols are in front of page.
Edit: I've also found that if I view the source code before and after clicking the button, the button is indeed refreshing the code and adding the desired items. The problem seems to be exclusively in trying to refresh the partial.
Any help is appreciated. Thanks!

It seems your rjs file has some invalid bits at the start. Maybe try to re-create the file?

What did you expect to do with render(#team) ?
I've taken a look at the action view's method "render" and didn't found how you were expecting it to function. Maybe there is another functionality that you are aware and I don't.
You can also use erb and not rjs, using it just like a view

Along the lines of Bert Goethal's answer, is your editor saving your text file as UTF-8 with BOM?
A BOM will add two unicode encoded characters to the beginning of the file, and that might be where those are coming from...

Related

Passing rails variable to liquid works in console but not in view

I want to pass a hash to the render method. In my console everything works fine when I do this:
#object = Object.find(params[:id])
#hash_object = #object.to_liquid
#template = Liquid::Template.parse("Welcome to {{object_title}}")
#template.render('object_title' => #hash_object["title"])
But when i want to render the page through my controller and pass it through an app-proxy which expects vanilla liquid, the hash-key isn't appearing. But it's interpreted, because the view shows blank space. If it wouldn't work at all, the view would show:"Welcome to {{object_title}}" or don't even load because of syntax errors.
I tried almost every possible way to render the template. The next two tryouts are the ones which do not throw an error, but show only a blank where the title should appear:
#pageview = Liquid::Template.parse(File.read(Rails.root + "app/views/app_proxy/show.html.erb"))
render text: #pageview.render('object_title' => #hash_object["title"]), content_type: "application/liquid"
And the second one (which I think is a bit cleaner and more rubylike):
respond_to do |format|
format.html do
render text: #pageview.render('object_title' => #hash_object["title"]), layout: false, content_type: "application/liquid"
end
end
Where is the mistake in these renderings or what am I missing?
# variables are assigned to an instance of a class, not the class itself, so you need to declare it an "initialize" method (or "setup" method, if a test)
render html: instead of render text:

How do you call a model's show url from a Rail create controller?

I'm having trouble calling a model's show path from within a create controller.
I'm using the Koala gem in a Rails 3.2 app. I'm trying to publish to Facebook's open graph automatically when a User creates a particular record type.
I have a page set up with all the required FB meta tags.
I can run the Koala methods from the console and everything works fine.
But if I try to run this from the controller I get an error.
My controller looks like this:
def create
#fb_model = current_user.fb_models.build(params[:fb_model])
if #fb_model.save
Koala::Facebook::API.new(app_token).put_connections( current_user.fb_uid, "namespace:action", :object => fb_model_url(#fb_model) )
respond_to do |format|
format.html { redirect_to(#fb_model, :notice => 'Successfully created.') }
format.xml { render :xml => #fb_model, :status => :created, :location => #fb_model }
end
else
respond_to do |format|
format.html { render :action => "new" }
format.xml { render :xml => #fb_model.errors, :status => :unprocessable_entity }
end
end
end
When I create a record, my logs show:
Koala::Facebook::APIError (HTTP 500: Response body: {"error":{"type":"Exception","message":"Could not retrieve data from URL."}}):
If I edit the controller to use a static url for testing, everything works fine.
...
if #fb_model.save
Koala::Facebook::API.new(app_token).put_connections( current_user.fb_uid, "namespace:action", :object => "http://myapp.com/fb_model/2" )
...
Why can't I pass the record's url to FB from within the create controller using fb_model_url(#fb_model)?
I eventually got to the bottom of this. It's actually a really frustrating issue, as there is no indication that this is the problem in any logs or elsewhere.
The problem was that I was deploying/ testing on Heroku, and only had 1 web dyno running. My app was unable to handle both the Facebook request and the post/ get simultaneously, causing the error.
This has been addressed in another question Facebook Open Graph from Rails Heroku. It's really not what I was expecting, and I didn't come across this question in any of my earlier searching. Hopefully this can help someone else.
I solved the issue by switching from thin to unicorn.
build is finalised when the parent model is saved, and you dont seem to be operating on a parent.
I think you actually want this:
#fb_model = current_user.fb_models.new(params[:fb_model])
Also you seem to be calling #fb_model.save twice which is wrong.
Thanks for posting your findings - I've been dealing with this issue for the past couple of days and wouldnt have figured that. So when you simply increased your dyno load, you no longer had this error? I was on the verge of just using the Javascript SDK even though my 'put_connections' callbacks work in the heroku console.

Rails 3 rendering template missing without file ending

I have an action in my controller as below:
def show
#post = Post.find_by_setitle(params[:setitle])
if !#post
render 'error_pages/404'
return
end
respond_to do |format|
format.html
end
end
If the render error_pages/404 I get a template missing. Switching it to render error_pages/404.haml.html works fine.
Why is this?
N.B. There is no actual error_pages controller or model. Just a convenient place to keep them.
Edit: I'm using mongoid and hence don't have access to ActiveRecord. Controller base can't be looking for a particular ActiveRecord exception?
From the documentation
The render method can also use a view that’s entirely outside of your application (perhaps you’re sharing views between two Rails applications):
Rails determines that this is a file render because of the leading slash character. To be explicit, you can use the :file option (which was required on Rails 2.2 and earlier):
You need either to pass the :file option, or to start the location string with a slash. Alternatively, you could use the Rails functionality to rescue from errors, and recover from ActiveRecord::RecordNotFound with a 404. See this post for details.
You should probably use render :template => 'error_pages/404'.
I think Rails is looking for a partial called _404.
Try it out 1:
render 'error_pages/404' (and name the file _404.html.erb)
Try it out 2:
render :template => 'error_pages/404' (and name the file 404.html.erb i.e. no leading underscore)

Partial not updated on first click

I am having problems with a remotely executed action and a partial that doesn't update the first time I click the link.
Inside the view (a partial named books) I am creating a link:
link_to "⊗", read_book_path(book), :remote => true
The read_book_path is defined in routes.rb
There is also a conditional that displays a different text when that book is read.
Inside my controller, I have defined a new action:
def read
#books = Book.all
#book = Book.find(params[:id])
#book.read = !#book.read
#book.save
respond_to do |format|
format.html { redirect_to(books_url) }
format.js {render :layout => false, :locals => { :book => #book } }
end
end
This means I need a file read.js.erb, this file's content is:
$("#books").empty().html("<%= escape_javascript( render(:partial => "books") ) %>");
When I click the link, I can see in the terminal window that the database field is updated but the partial is not. Clicking the same link again updates the partial.
Changing the link to :remote => false also works but the page reloads (as expected).
I have tried to debug it with Safari and the Developer tools and I can see the server's response when clicking the link for the first time.
Something is wrong there, the HTML generated by <%= escape_javascript( render(:partial => "books") ) %> contains the wrong HTML with the old content of the partial. Only the second or third click shows the updated HTML.
I have integrated jquery-ujs - is that the reason the partial doesn't update the first time or am I missing something else?
This really gave me a headache, can you help me?
Edit:
If that helps: I created a listener in application.js to ajax:before and ajax:complete. The first one shows a little spinner, the second one hides it.
When I click the link, the spinner shows but it doesn't hide.
It looks like you have an ordering problem that's causing the trouble. You're capturing a complete set of books into the #books variable and then modifying a separate copy of a single book. This change will not be propagated back.
# Load and modify the one book by flipping the flag
#book = Book.find(params[:id])
#book.read = !#book.read
#book.save
# Load all books
#books = Book.all
As a note this is an extremely inefficient way of doing things, so I hope you're not working on a large amount of data. You might find it's easier to do this by simply toggling the one field with a simple UPDATE query:
Book.update_all({ :read => true }, { :id => params[:id] })
I'm not sure why you're calling $(...).empty().html(...) instead of simply $(...).html(...) since the html() method should replace the HTML wholesale with no need to clear it in advance.
One thing that might help is using .js.rjs where the equivalent would be:
page[:books].replace_html(:partial => 'books')
With simple JavaScript, RJS allows you to eliminate a lot of the drudgery. You can use JS in RJS as well for cases where there is no equivalent:
page << '$("#books").empty()'
page[:books].replace_html(:partial => 'books')
To make this more Rails friendly, you could call your partial _book which would make the local variables redundant. Each partial has a default variable with a name matching the template name:
render(:partial => 'book', :collection => #books)

Returning from rails controller

Here's a beginner rails question...
After I do:
format.xml { head: ok}
How do I return from the controller endpoint without showing the view? If I drop off the end of the function at this point, I get what I expect, but if I call 'return', I end up in the view (or in my case in a missing view template). I can code up lots of if/else etc., but it would be nice to early out from the function without ending up in a view template.
I've searched around and can't figure out what the obvious answer is to this; it must be straightforward...
You can use "render :nothing => true, :status => :ok" to return without rendering anything, once you have send a render :nothing => true you need to return from the controller, something like this might work. You can swap the head() method call for a render => :nothing followed by a return, the head() method is documented here:
api.rubyonrails.org/classes/ActionController/Base.html#M000635
Here's the code that should do it for you...
gist.github.com/126367
Ping me if that doesn't properly answer your question, documentation for the render call with some helpful user comments can be found here:
apidock.com/rails/ActionController/Base/render
(sorry I couldn't hyperlink the links for you, as a new user stackoverflow won't allow me to post more than one!)
Use
render :nothing => true, :status => :ok
in your action method
I guess you must be asking for :
render :nothing => true

Resources