问题
I'm just learning Rails and would appreciate any help. I've looked at probably 10 tutorials for :remote => true
on form_for
and they all seem to copy each other (equally confusing).
This tutorial is one of them: http://tech.thereq.com/post/18910961502/rails-3-using-form-remote-true-with-jquery-ujs
My web app is pretty much all on one page, and my 'submit form' is inside a pop-up lightbox. This means that the form_for code is actually within my index.html.erb. It also means a new @playlist instance variable is created for index
(instead of having this be in new
)
My end goal is this:
if @playlist.save
returns true
, I want to REDIRECT the user to the root_path
WITH a :notice. There is no need to update the form with a success message or anything like that. I want a hard redirect on save success.
if @playlist.save
returns false
, I want to render the code inside create.js.erb, which will append the errors into the lightbox form without refreshing the page. note A lot of the tutorials seem to want to re-render the entire form as html, then replace the contents in place. I'd rather (if I can), just send the errors to the form and insert them, I think re-rendering and replacing the entire form seems more complicated than it has to be.
As of right now, my code is kind of muddled, especially:
- the
respond_to
block. This is the largest point of confusion about what actually goes here, I have tried lots of different code and nothing works - I have no idea if create.js.erb is correct
- I have no create.html.erb - I assume this is right because I just want to redirect
First line of my form:
<%= form_for @playlist, :remote => true do |f| %>
My entire PlaylistsController
class PlaylistsController < ApplicationController
before_filter :load_genres, :only =>[:index, :user]
before_filter :new_playlist, :only => [:index, :new, :create]
def index
@playlists = Playlist.order('created_at DESC').page(params[:page]).per(30)
end
def new
end
def create
respond_to do |format|
if @playlist.save
# ???
format.html { redirect_to root_path, :notice => "Playlist submitted" }
else
# ???
format.js { render :js => @playlist.errors, :status => :unprocessable_entity }
end
end
end
def user
@playlists = Playlist.order('created_at DESC').where(:username => params[:username]).page(params[:page]).per(30)
end
def listen
playlist = Playlist.find(params[:playlist_id])
playlist.update_attribute(:listens, playlist.listens + 1)
render :nothing => true
end
private
def load_genres
@genres = Genre.order(:name)
end
def new_playlist
@playlist = Playlist.new(:title => params[:title], :url => params[:url], :description => params[:description])
end
end
create.js.erb
jQuery(function($) {
alert('createjs called');
$('#submit-form form').on('ajax:error', function(event, xhr, status, error){
var responseObject = $.parseJSON(xhr.responseText),
errors = $('<ul />');
$.each(responseObject, function(index, value){
errors.append('<li>' + value + '</li>');
})
$(this).find('.submit-playlist-errors').html(errors);
});
});
回答1:
If I understand you correctly, you have a form and you want to redirect with flash
notice if the form is saved. If the form is invalid you want do display errors.
You can send the form (or any request) to rails app in different formats (usually html, json and js). This is specified in the url you provides.
playlist_path(@playlist)
# => /playlists/1
playlist_path(@playlist, :format => "json")
# => /playlists/1.json
playlist_path(@playlist, :format => "html")
# => /playlists/1.html
# ... etc
The format tells rails which kind of response specified in your respond_to
block to use.
Now if this is clear you have to decide which format to use.
If you specify js
format, the response will be treated as script
an executed. If the form is valid, you can send user javascript that will redirect them to the page you desire. If the form is invalid, you can modify HTML in the way so you can display error messages. No client-side code needed.
respond_to do |format|
if valid
format.js { render "valid" }
else
format.js { render "invalid", :status => :unprocessable_entity }
end
end
# valid.js.erb
window.location = <%= your_path %>
# invalid.js.erb
// whatever to display errors
When you use json
you can return redirect url to redirect user or errors if the form is invalid. Note that this solution requires Javascript on the client side to handle it.
# controller
respond_to do |format|
if valid
format.json { render :json => your_path }
else
format.json { render :json => @object.errors, :status => :unprocessable_entity }
end
end
# client side javascript
$("form")
.on("ajax:success", function(event, data, status, response) {
window.location = data
})
.on("ajax:error", function(event, response, error) {
// logic to handle errors
})
You can also use html
format (by setting format to html
or not specifying format at all). But if you use :remote => true
you will have to treat it the same way as json
(have client side javascript). If you use redirect_to
as a response, it will redirect the request, not your user.
I am not sure about displaying the flash message after the user is redirected but you can try it this way:
respond_to do |format|
if valid
format.html {
flash[:notice] = "Playlist submitted"
render :json => your_path }
else
format.html { render :json => @object.errors, :status => :unprocessable_entity }
end
end
# client side javascript
//...
Hopefully this will dry your respond_to
block.
来源:https://stackoverflow.com/questions/12568887/remote-true-confusion-with-form-for