So I have the following form:
<%= form_tag url_for(:controller => 'profile', :action => 'follow_topic'), :remote => true do %>
<%= hidden_field_tag :topic_id, topic_id %>
<%= content_tag :button, :class => 'link', :onclick => "javascript:document.getElementById('followtopic#{Topic.find(topic_id).identifier}').innerHTML='Following...'" do %> Follow <% end %>
<% end %>
and I'm trying to get the controller to process it as JS in place of HTML. The funny thing is I have a form exactly like this in another spot in the app that seems to work fine, and the controller definitions are the same. Can't quite figure out the problem. Any ideas on what I should be checking first?
def follow_topic
#topic = Topic.find(params[:topic_id])
current_user.follows << #topic
respond_to do |format|
format.js
end
end
You got it right except your format.js isn't doing anything. What are you expecting in your form submit? and what are you expecting in return? a json or http response 200?
specify that in your format.js like so:
...
respond_to do |format|
format.js { render :nothing => true, :response => :ok if current_user.follows << #topic }
end
...
or something to that effect.
This question is OLD but it's unanswered and I just struggled with the same problem for hours, so hopefully this will help someone in future.
Make sure app/assets/javascripts/application.js contains:
//= require jquery
//= require jquery_ujs
And that erb contains <%= javascript_include_tag "jquery", "jquery_ujs" %> and not just a <script> tag.
This is what fixed it for me.
Related
I'm trying to render a javascript file (through a remote AJAX call) using the following code:
respond_to do |format|
format.js { render "like", :locals => {:media_id => media_id, :like_type => like_type}}
end
The file is named "like.js.erb" and I know it will work because when I put just a standard javascript alert in the file, it works perfectly.
The file (like.js.erb) looks like this:
<% if like_type == "l" %>
alert("liking as <%= like_type %> for media_id <%= media_id %>");
$('like_<%= media_id %>').update("liked");
<% elsif like_type == "u" %>
alert("unliking as <%= like_type %> for media_id <%= media_id %>");
$('like_<%= media_id %>').update("unliked");
<% end %>
When the file contains the code above, the POST action completes properly but nothing is returned at all. It seems that it doesn't like the multiple locals being passed.
Any ideas? Thanks!
If you use the :locals option then you need to provide the :partial key as a parameter.
respond_to do |format|
format.js { render :partial => "like", :locals => {:media_id => media_id, :like_type => like_type}}
end
or:
respond_to do |format|
format.js { render "like", :media_id => media_id, :like_type => like_type}
end
I have a submit form that is shown in a lightbox. I validate the form pretty heavily but there are circumstances where a playlist is already submitted, in which case I can't tell before a form is submitted.
Currently I have :disable_with => 'Submitting...'
It would be completely awesome if the error was sent back to the form, and the submit button would re-enable.
Would this be possible without too much complication?
I also have a second related question... Because my form is in a lightbox, it's code is actually ON the index page (my app is just one page pretty much). This means that there really is no 'new' action, but rather a #playlist = Playlist.new(:title => ...) in my index action (along with a #playlists = Playlist.all, etc). In my routes I did this: resources :playlists, :only => [:create]
Does this sound about right the way I did it?
EDIT: HEre is some code, although it's basically about as simple as you can imagine it.
The following kind of works... it creates the playlist if its valid, otherwise it does nothing. Both times create.js.erb is called.. i just dont now how to make this work to completion now. on success i need to close the window, on failure i need to load the errors into the form thats already on the screen. Im not sure where that goes though :/
before_filter :load_genres, :only =>[:index, :user]
before_filter :new_playlist, :only => [:index, :new]
def index
#playlists = Playlist.order('created_at DESC').page(params[:page]).per(30)
end
def create
#playlist = Playlist.new(params[:playlist])
respond_to do |format|
if #playlist.save
format.html { redirect_to root_path, :notice => "Playlist submitted" }
format.js {}
else
format.html { render :action => :new, :layout => !request.xhr? }
format.js {}
end
end
end
def new
end
def load_genres
#genres = Genre.order(:name)
end
def new_playlist
#playlist = Playlist.new(:title => params[:title], :url => params[:url], :description => params[:description])
end
Heres the first like of my form (located in index.html.erb):
<%= form_for #playlist, :remote => true do |f| %>
I currently have no html or code in create.html.erb
Here is my solution to this Issue.... I put these in all my js.erb files
$('#flash').html("<%= escape_javascript raw(flash_display) %>");
With this Helper
def flash_display
response = ""
flash.each do |name, msg|
response = response + content_tag(:div, msg, :id => "flash_#{name}")
end
flash.discard
response
end
this works well with the flash div already set up in layout
<div id="flash">
<% flash.each do |name, msg| %>
<%= content_tag :div, msg, :id => "flash_#{name}" %>
<% end %>
</div>
Hope this Helps
Without seeing your code I can only make broad suggestions.
One would be to set up a js.erb response to the controller action-- or you could do a js script tag in an if clause inside your HTML. Either way you would use jQuery to update the element.
Inside the js/html erb file:
jQuery('#flash_area).html(<flash message>);
The the flash area in the view would need an id of flash_area (or whatever you want to name it).
I'm sure this question has been asked before in a different context but I'm still so stuck with figuring out AJAX Rails and, I guess, Rails in general (kinda makes me wonder if I should just go back to PHP...). Well anyways I have this form that I want to AJAXify.
This is the "list" view which is part of the "subject" controller
<h1>Listing Subjects</h1>
<ul id="subject_list">
<% #subjects.each do |c| %>
<li><%= link_to c.name, :action => 'show', :id => c.id %></li>
<% end %>
</ul>
<p id="add_link"><%= link_to_function("Add a Subject",
"Element.remove('add_link'); Element.show('add_subject')")%></p>
<div id="add_subject" style="display:none;">
<%= form_tag(:action => 'create') do%>
Name: <%= text_field "subject", "name" %>
<%= submit_tag 'Add' %>
<% end %>
</div>
Code for my "subject" controller
class SubjectController < ApplicationController
def list
#subjects = User.find(:all)
end
def show
#subject = User.find(params[:id])
end
def create
#subject = User.new(params[:subject])
if #subject.save
render :partial => 'subject', :object => #subject
end
end
end
My "subject" partial
<li id="subject_<%= subject.id %>">
<%= link_to subject.name, :action => 'show', :id => subject.id %>
</li>
And the User is just a simple model I made that contains two columns "name" and "email".
How this code currently works is that when you click "Add", the textfield input is revealed. When you type something in the input and submit it, the "_show" partial is rendered in the create link. I was following a Rails 2.0 tutorial but I have 3.0 and I've read through some tutorials and they all mention ":remote => true" and jquery_ujs.js but I have no idea how to apply them to a "form_tag" rather than "form_for" Rails helper.
Basically I want to asynchronously add the element to the bottom of the list without a page load. I've really tried to understand absolutely all of the tutorials I could find but I just can't figure it out.
I believe that you'd better use some Unobtrusive JavaScript to tell to your app
and browser what exactly you want to render and how.
You want too much from simple render :partial => 'subject', :object => #subject line of code.
Here's my snippet that may be helpful to you.
# in the view (:remote => true for form_tag is not problem at all)
<%= form_tag({:controller => :products, :action => :empty_cart }, {:id => 'empty_cart', :remote => true}) do %>
<%= submit_tag 'Clear' %>
<% end %>
# in the controller (note that format.js section in the respond_to block)
def empty_cart
...
respond_to do |format|
format.html { redirect_to :root, :notice => 'Your cart is empty now' } # in the case of disabled JS support
format.js { render :js => "$('#empty_cart').fadeOut()" } # or you can place js code in the empty_cart.js.erb file and specify format.js here without the block
end
end
Check this article if I'm not clear enough.
I'm creating a simple demo app that allows a user to enter their email address to register their interest in receiving beta access. The app then sends them a confirmation email that lets them know we've received their request. If you've ever signed up to be notified of a beta launch then you get the idea.
I'm curious about how to handle errors in Rails 3 while using AJAX. Before implementing my respond_to block I had a form that rendered a shared errors partial.
Here's the form.
<% if flash[:notice] %>
<p><%= flash[:notice] %></p>
<% end %>
<p>Sign up to be notified when the beta launches.</p>
<%= form_for #user, :remote => true do |form| %>
<%= render '/shared/errors', :target => #user %>
<%= form.label :email, "Your Email Address" %>
<%= form.text_field :email %>
<%= form.submit "Notify Me" %>
<% end %>
And here's the aforementioned errors partial.
<% if target.errors.any? %>
<ul>
<% target.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
<% end %>
Very standard stuff. The controller action looks like this.
def create
#user = User.new(params[:user])
respond_to do |format|
if #user.save
format.html { redirect_to :back, flash[:notice] = "Thanks for your interest! We'll let you know when the app is in beta." }
format.js
else
format.html { render :action => :new }
format.js
end
end
end
Everything works perfectly before implementing ajax. If the form passes validation then they see the success flash message and if not then they see a list of errors. So now that i have a create.js.erb file how should I handle the errors without repeating myself or is that impossible. I obviously want to keep this as DRY as possible.
You can still render a shared partial for all .js errors in your js.erb file.
<% if #user.errors.any? %>
var el = $('#create_user_form');
// Create a list of errors
<%= render :partial=>'js_errors', :locals=>{:target=> #user} %>
<% else %>
$('#users_list').append("<%= escape_javascript(render :partial=>"users/show", :locals=>{:user => #user }) %>");
// Clear form
el.find('input:text,textarea').val('');
el.find('.validation-errors').empty();
<% end %>
And your partial could look like (Assuming jquery):
<% target.errors.full_messages.each do |error| %>
var errors = $('<ul />');
errors.append('<li><%= escape_javascript( error ) %></li>');
<% end %>
But there's also ANOTHER option...It's even DRYer.
http://www.alfajango.com/blog/rails-3-remote-links-and-forms/
If you are working your way through ajax in rails 3, this guide is really the best for understanding responses and ajax rendering as it currently stands.
I worked through this guide and posted in the comments how you can actually use your HTML partials for both HTML and AJAX request responses. I did it by accident and then followed up on how to do it.
Enjoy!
You can actually return straight-up html with your response just like before.
Here's the short version:
def create
#something = Somethng.new(params[:something])
if #something.save
respond_with( #something, :status => :created, :location => #something ) do |format|
format.html do
if request.xhr?
render :partial => "something/show", :locals => { :billable => #billable }, :layout => false
end
end
end
else
respond_with( #something.errors, :status => :unprocessable_entity ) do |format|
format.html do
if request.xhr?
render :partial => "something/new", :locals => { :something => #something }, :layout => false
else
render :action => :new
end
end
end
end
end
I'm not sure the rails remote form way to do it, but my standard mode of operation is to return objects on ajax request in this format:
{ success: true|false,
data: "html or some other data",
errors: {} } // jsonified ActiveModel::Errors object
It works very well and lets you render partials into the data field for use on the page, or you can loop through errors in the error object to insert error messages or highlight fields.
I have been facing the same problem a few days ago. I used remote => true option in my form to use Ajax in my Rails 3 application. After that, I have been looking for solution for validating my form fields. After trying a good number of jQuery / Javascript approaches (none of them worked for me though) I came to know about a superb gem called client_side_validations. It is very easy to install by following the instructions on github link (https://github.com/bcardarella/client_side_validations). It works like charm for client side validation of form fields, an awesome gem indeed. Hope this helps with people who are tired of looking for a simple solution for client side validation of model fields after using Ajax in Rails 3 application.
I'm trying to prepare a json object for my rails app.
Here is my code:
#videos_controller
def show
#video = Video.find(:all,
:conditions => { :published => true, :trash => false },
:order => 'RANDOM()', :limit => 1)
respond_to do |format|
format.html # show.html.erb
format.json {render :partial => "videos/show.json"}
end
end
#_show.json
<%= #video.each do |video| %>
{
"video_link": "<%= video.link %>",
"video_id": "http://website.com/videos/each/<%=video.id%>"
}
<% end %>
but at videos/show.json I'm getting something like that
{
"video_link": "http://www.youtube.com/watch?v=6rmWnwtps6I",
"video_id": "http://website.com/videos/each/51"
}
#<Video:0x220a060>
How to avoid the nasty last line and were does it getting from? I think, becouse of that, it doesn't allow me to work with json object properly. I know, that answer is pretty simple, but just can't get it. Thank you in advance.
Take out the equal sign in the line <%= #video.each do |video| %> so it's just <% #video.each do |video| %>. The segment you're seeing is the default to_s method which is being returned from the each method.
Change this:
<%= #video.each do |video| %>
to this:
<% #video.each do |video| %>
Since you’re outputting text in the body of the loop, you don’t want to output the loop itself (the result of which is the enumerable itself).