I'm trying to implement ajaxy signup with rails 3. I'm using jquery-ujs and remote form. I access the signup form with $.get request, and it is displayed correctly. This signup form is remote:
form_for #user, :remote => true, :html => {"data-type" => "html"} do |f|
In my application.js, if the ajax request for getting the form is successful, I'm trying to bind handler for ajax events from unobtrusive javascript:
var load_remote_form = function(evt) {
var href = $(this).attr('href');
// load form template
$.get(href, {}, function(data) {
$('body').append(data);
$('form[data-remote]').bind("ajax:beforeSend", function(e) {
console.log("Caught beforeSend!");
});
});
evt.preventDefault();
};
$(document).ready(function() {
$('a#signup').click(load_remote_form);
});
Chrome's development tools show that the event "ajax:beforeSend" is binded, but it is never handled (I have nothing in the javascript console when I send the form, though in rails log I see that the request is processed correctly and the response is send). I can bind other events to the same selector (form[data-remote]), like click, and they are handled correctly.
Ajax events binded through .live are not handled as well. But if the form is rendered as part of the layout (i.e. it is on stand-alone page like http://localhost:3000/signup/), binded "ajax:beforeSend" is handled correctly.
My controller (just for a case, it may be badly written, but I'm pretty sure it works):
class UsersController < ApplicationController
layout :layout_for_type
def new
#user = User.new
end
def create
#user = User.new(params[:user])
if #user.save
session[:user_id] = #user.id
flash[:notice] = "You have successfully registered."
redirect_to root_url
else
if request.xhr?
render :action => 'new', :status => :unprocessable_entry, :layout => false
else
render :action => 'new'
end
end
end
def layout_for_type
request.xhr? ? nil : "application"
end
end
What am I doing wrong? May be there is a better approach for implementing such "double-ajaxed" forms?
Silly me. I've completely overlooked another potential source of problems. I had
javascript_include_tag :all
in my application layout, and that caused including both jquery.js and jquery.min.js into my page. It turned out to be the cause of that strange behavior. Removing jquery.min.js did the trick. Hope that might be useful for someone someday.
Related
I'm trying to stub the model method which I'm using in my controller, but it never seems to be working. Can someone let me know the proper way to do it
User Controller
if current_user.user_token
#user = #account.users.find(params[:id])
#user.revoke_seat(:admin, current_user)
render :template => "/admin/users/revoke_seat"
else
render :js => "window.location.href='#{server_url}/oauth/authorize?response_type=code&client_id=#{client_id}&state=#{request.referrer}?auto_revoke_seat=true&redirect_uri=#{auth_service_callback_url}";
end
Rspec
before do
users(:admin).stub(:internal_admin?).and_return(true)
login_as :admin
user.stub(:user_token).and_return("123123")# THIS IS NOT WORKING
end
it "should redirect to authentication service to generate access token" do
expect(user).to receive(:user_token).and_return(true)
xhr :put, :revoke_seat, account_id: account.id, id: user.id
expect(response).to render_template('admin/users/revoke_seat')
expect(assigns(:account)).to eq(account)
expect(assigns(:user)).to eq(user)
end
You might try the allow approach instead of stub. E.g., allow(:admin).to receive(:internal_admin?).and_return(true)
I always get the following error:
AbstractController::DoubleRenderError (Render and/or redirect were
called multiple times in this action. Please note that you may only
call render OR redirect, and at most once per action. Also note that
neither redirect nor render terminate execution of the action, so if
you want to exit an action after redirecting, you need to do something
like "redirect_to(...) and return".):
The error happens, when it id is nil the first, but not the second time...
def calc_next
id = next()
if id.nil?
id = next_next()
if id.nil?
render :layout => false, :format => :js
else
redirect_to :action => "view", :id => id, :format => :js
end
else
redirect_to :action => "view", :id => id, :format => :js
end
end
I don't see the problem in this redirection, as the outer one is fine. Even with the debugger there are not two redirections at the same time...
Any help is appreciated...
Markus
This looks like some kind of helper function rather than a Controller action. In which case you're probably calling calc_next twice in one action, or render / redirect_to from somewhere else in the same action. Remember that render and redirect_to don't immediately cause the Controller to return.
Check whether your control path can both call calc_next and call render or redirect_to from somewhere else (or from a second call into calc_next).
If you post the controller action you're going through, we may be able to help better.
Are there any before_filters that might be rendering or redirecting?
You have two options also:
redirect ... and return
render ... and return
I have a column in a table called Complete that is a boolean.
How can I (using the Rails 3 / JQuery way) provide a link that will toggle that via AJAX?
Historically, I've simply created my own jquery file, grabbed the click event, and done it by hand. But it really seems like I'm missing something by not doing it the "rails" way. If that makes sense.
I guess I still don't understand how the responds_to JS works, JS with ERB, etc.
Is there a good, up-to-date tutorial on how to do this?
Thanks.
see this post,
Rails 3, Custom Actions, and HTML request methods
and use UJS on top of it.
so you have a fallback, if javascript is disabled
a possible method in the controller looks like that:
# GET /surveys/1/close
def close
#survey.close!
flash[:success] = "Survey successfully closed!"
respond_to do |format|
format.html { redirect_to(surveys_url) }
format.xml { head :ok }
format.js { render :partial => 'list_item', :locals => { :survey => #survey } }
end
end
you could also use a state machine to change the state of your object.
okay, so basically, I have a normal form for my model:
= form_for #operator do |f|
blah blah blah
In my operators controller, i have this:
def new
#operator = Operator.new
#operator.build_user
respond_to do |format|
format.html {}
end
end
def create
#user = User.create(params[:operator].delete(:user))
#user.update_attributes(:login => #user.email)
#operator = Operator.new(params[:operator].merge(:user => #user))
respond_to do |format|
if #operator.save
format.html {redirect_to new_operator_aircraft_path(#operator)}
else
format.html { render :action => "new", :error => #operator.errors }
end
end
end
very basic stuff. I have some validates_presence_of stuff in my model so naturally when I submit my form, it should show me that I have errors(and keep the fields I have filled up)
Right so far? yeah. The problem is, it seems I am posting to /operators and that's what renders. I seem to have forgotten about what happens in Rails2.3+ but shouldn't I be redirected to /operators/new again? or was that the intended behavior all along?
Here's what I think you are asking:
After I submit a form with errors, why does the URL
read "/operators" rather than
"/operators/new".
Thanks to resourceful routing, when submitting a form via POST to "/operators" the create action is called on the OperatorsController. If you encounter errors when saving your operator, you've instructed the controller to render the new action within the same request.
render :action => "new", :error => #operator.errors
This means a redirect is not occurring and therefore the URL remains "/operators".
If a redirect were to occur, you would lose all the state information of the #operator object in the current request, including the errors you encountered as well as the form values you just submitted.
In other words, working as intended.
I am using remote form in Rails 3. It works fine but I want to show / hide spinner during ajax request.
In rails 2.3.* we use :before & :after in remote form to show/hide spinner
What should I do in Rails 3, as remote form of Rails 3 doesn't contain such options.
Here is a working solution I tried:
In my view file, I use :onSubmit to show a spinner:
<% form_for("", #search,
:url => {:action => "search"},
:html => {:id => "search_form",
:onSubmit => "$('search-loader').show();"},
:remote => true) do |f| %>
In my search action, I added one line to hide it:
render :update do |page|
...
page << "$('search-loader').hide();"
end
It works great..!
Well, I'm using jQuery, and I'm doing the following, trying to be unobtrusive:
Add this, right before your </head> tag:
= yield :document_ready
Then in your application_helper.rb:
def document_ready(content)
html = %{ $(function(){#{content}})}
content_for(:document_ready){ javascript_tag(html) }
end
This allows you to load and run javascript once your document is loaded.
On top of the view containing your form add:
- document_ready("hide_button_show_spinner('your_button_id')")
In application.js
function hide_button_show_spinner(element_id) {
$('#'+element_id).bind('click', function() {
$('#'+element_id).after("<img src='/path/to/your/spinner.gif' class='ajax_loader' id='"+element_id+"_ajax_loader' style='display: none'/>")
$('#'+element_id).hide();
$('#'+element_id+'_ajax_loader').show();
});
}
This will hide the button and show the spinner once the button is clicked. You may need to adapt this to your specific case.
You can then show the button and hide the spinner in your javascript response (the .js.erb file that you render from the action called by the ajax request).