Trying to implement an Ajax function rails 3 .load() - ruby-on-rails-3

This is my first time trying to implement an Ajax call in rails 3, though I am using the .load function ( I still hope this is Ajax otherwise im understanding this incorrectly)
So i have a search form that returns results via a get request which renders on a different page, i would like the results to appear on the same page as the search form
<%= form_tag({:controller => 'search', :action => 'search'}, {:method => 'get'}) do |select| %>
<%= label_tag :search, "Enter Keywords Here" %>
<%= text_field_tag :search, params[:search] %>
(I have shortened the form)
<%= submit_tag "Search", :class => "searchbutton" %>
<% end %>
Jquery/Ajax call
$(document).ready(function() {
$('.searchbutton').click(function() {
$('#searchres').load('shared/searchresults');
});
});
View
<h3>Search Recipes here</h3>
<%= render 'shared/searchrecipes' %>
<div id ="searchres">
</div>
What am i doing wrong?

Due to this being an AJAX call, you need to add remote: true besides method: :get, getting an html parameter hash like this:
{:method => 'get', :remote => true}
When Rails finda remote call, it prevents the default automagically. Otherwise, you would need to modify you javascript like this:
$(document).ready(function() {
$('.searchbutton').click(function(evt) {
$('#searchres').load('shared/searchresults');
evt.preventDefault();
});
});

Related

ajax .keyup search function

I have a search function that uses the .keyup method on a rails application. I know that the call is working because the first letter I type is searching and showing results. If I continue to type it doesn't continue to search the method. Here is my jquery below and the part of my rails view it is calling.
JQuery
$("input#search").keyup(function (){
$.get($("#verified_search").attr("action"), $("#verified_search").serialize(), null, "script");
return false;
});
index.js.erb
$(".results").html("<%= escape_javascript(render("search")) %>");
index.html.erb view
<%= form_tag admin_view_index_path, :method => 'get', :id => 'verified_search' do %>
<%= text_field_tag :search, params[:search] %>
<%= submit_tag "Search", :name => :nil %>
<% end %>
<%= render 'search' %>
Use .live()
$("input#search").live('keyup', function (){
$.get($("#verified_search").attr("action"), $("#verified_search").serialize(), null, "script");
return false;
});
When you replace the content of $('.results') in index.js.erb, any listeners associated with those elements are gone.
http://api.jquery.com/live/
Edit: As it says in the link, the .live() method is deprecated as of jQuery 1.7. Use .on() to attach event handlers. Users of older versions of jQuery should use .delegate() in preference to .live().
Try this
$(document).on("keyup", "#verified_search", function(){
$.get($("#verified_search").attr("action"), $("#verified_search").serialize(), null, "script");
return false;
});

simple_form - how do I create radio buttons with nested input text boxes

I'm using simple_form to render my forms and trying to get the following behavior: I want the client to choose from 3 options. In every option he supplies additional field or two.
So I'd like something like this:
Please set your preferences:
o Pay me on a specific day - [input field to get the day]
o Pay me a specific amount of money - [input field for the amount]
o Pay me on a regular basis - [radio buttons to choose between weekly/monthly basis]
I can create the radio buttons as follows, but can't add nested fields under them:
<%= simple_form_for #client, action: 'edit_payment_method' do |f| %>
<%= f.input :payment_type, label: 'Please set your preferences:',
collection: [ ['Pay me on a specific day', :specific_day],
['Pay me a specific amount of money', :specific_money],
['Pay me on a regular basis', :regular_basis]
], as: :radio_buttons %>
<%= f.button :submit, 'Submit' %>
<% end %>
What would be the best way to create the nested text boxes?
As for the fields, I don't need to send them to different controllers (per payment_type), it's fine if I send them all to one method and read the relevant values according to the payment type he chose.
Thanks! Zach
The simple_form collection_radio_buttons is likely what you want. Its options parameter accepts a block which allows you to customize what is rendered with each radio button. Take a look at the example in rdocs here.
Edited:
Here is basically what you need to do in a relatively generic way (hasn't been tested, but I'm running something similar). Put your additional controls in the partial for each radio button:
<% radio_buttons = [
{ :text => 'Pay me on a specific day', :value => :specific_day, :partial => "<textbox_partial_name>", :locals => { :any_locals => :your_partial_needs} },
{ :text => 'Pay me a specific amount of money', :value => :specific_money, :partial => "<textbox_partial_name>", :locals => { :any_locals => :your_partial_needs} },
{ :text => 'Pay me on a regular basis', :value => :regular_basis, :partial => "<radio_partial_name>", :locals => { :any_locals => :your_partial_needs} },
] %>
<%= simple_form_for #client, action: 'edit_payment_method' do |f| %>
<%= f.label t("account.update_payment_method.title") %>
<%= f.collection_radio_buttons :payment_type, (collection.collect do |r| [r[:text], r[:value], r[:partial].nil? ? "" : r[:partial], r[:locals].nil? ? {} : r[:locals]] end), :second, :first do |builder| %>
<%= builder.label{builder.radio_button(:class => 'payment_method_options') + builder.text} %>
<% unless builder.object[2].blank? %>
<%= render :partial => builder.object[2], :locals => builder.object[3] %>
<% end %>
<% end %>
<%= f.button :submit, 'Submit' %>
<% end %>
You can omit :partial for any radio button that doesn't need additional controls, along with :locals if your partial doesn't need it. There are also ways to simplify this code for your situation, but this example illustrates how to add more complex control structures to each radio button if needed.
OK.. I've managed to solve this somehow, not sure that it's the best alternative, but I'm posting it so if someone needs it in the future he at least has something to start with.
I went with creating a "regular" form using simpleform and then using JQuery to move the inner input fields (which were created regularly) next to the radio buttons.
Add JQuery support to your rails app:
add gem "jquery-rails" to your Gemfile
bundle install
rails generate jquery:install
The form I've used (regular simpleform):
Notice the class that is attached to the radio buttons and the ids that are attached to the input fields. I'll use it later to move the elements.
<%= simple_form_for #client, url: 'update_payment_data' do |f| %>
<%= f.input :payment_type, label: t('account.update_payment_method.title'),
input_html: { class: 'payment_method_options' },
collection: [ [t('account.update_payment_method.sum_based.title'), :amount],
[t('account.update_payment_method.days_in_month_based.title'), :days_in_month],
[t('account.update_payment_method.optout.title'), :optput]
], as: :radio_buttons %>
<%= f.input :payment_amount, label: "Payment amount threshold",
input_html: { id: 'payment_amount_box' } %>
<%= f.input :payment_days_in_month, label: "Payment days in month",
input_html: { id: 'payment_days_in_month_box' } %>
<%= f.button :submit, t('account.update_payment_method.update') %>
<% end %>
In the same page - the JQuery code:
<script>
$(document).ready(function() {
var amount_box = $("#payment_amount_box");
var amount_box_parent = amount_box.parent();
amount_box.detach().appendTo($(".payment_method_options:eq(0)").parent());
amount_box_parent.remove();
var dim_box = $("#payment_days_in_month_box");
var dim_box_parent = dim_box.parent();
dim_box.detach().appendTo($(".payment_method_options:eq(2)").parent());
dim_box_parent.remove();
});
</script>
I think it's pretty self-explanatory, it just looks for what is going to be the inner input fields (by id) and moves them into the appropriate place under the span that simpleform creates for each radio button.
I had to play a little bit with the css to make it look how I wanted (display:block for example), but that's more or less it.
Hope it helps.. Zach

Partial not accessing local variable

I am rendering a partial like so:
<% #pages.each do |page| %>
<%= render 'layouts/pagewithchildren', :locals => { :page => page } %>
<% end %>
But when i try to access a variable in page i am getting the error:
undefined local variable or method `page'
I am accessing the variable like:
<%= page.title %>
So what else do I need to do?
i'm not 100% sure but isn't it either
<%= render 'layouts/pagewithchildren', :page => page %>
or
<%= render :partial => 'layouts/pagewithchildren', :locals => { :page => page } %>
?
You have to explicitly specify partial, otherwise, Rails will treat locals as a params hash, you can access locals[:page] but not page variable directly in your partial.
Change your code to:
<%= render partial:'layouts/pagewithchildren', locals: {page: page} %>

Rendering the Devise edit Password Form

I'm trying to render the Devise edit password form within another view because I don't want to duplicate the edit pw logic.
I've tried the following (after generating the Devise views):
<%= render 'devise/passwords/edit' %>
<%= render 'devise/passwords/form' %>
And a number of other variations on render that all seem to give me the same error:
"ActionView::MissingTemplate in foo#foo
Missing partial devise/passwords/edit..."
This variation:
<%= render :file => 'devise/passwords/edit.html.erb' %>
Gave me some hope but the following error:
"undefined local variable or method `resource' for #<#:0x47ef0e0>"
around this line:
<%= form_for(resource, :as => resource_name, :url => password_path(resource_name), :html => { :method => :put }) do |f| %>
That makes me think I'm close (as that is code from the form that I want) but shouldn't that template be using the correct logic from the hidden Devise controller? Or do I need to do something in the routes file to get this to work?
Am I way off?
Try this:
<%= render :template => 'devise/passwords/edit',
:locals => {
:resource => my_user_model_variable,
:resource_name => my_user_model_name } %>
Where:
my_user_model_variable could be current_user
my_user_model_name could be "User"

Ajax Callbacks in Rails 3 with Prototype, not jQuery

I'm upgrading an app from Rails 2 to 3 and am reworking all of the remote functions to use Unobtrusive Javascript. Where I'm struggling is handling ajax callbacks in UJS.
There are a lot of resources I've found that show how to implement these callbacks with jQuery, but not much for prototype. Perhaps you can help me figure this out.
In Rails 2, I had this:
<% remote_form_for #foo, {:loading => "loading_function()", :complete => "complete_function()" } do |f| %>
...
<% end %>
In Rails 3, I have this:
<%= form_for #foo, :remote => true do |f| %>
....
<% end %>
From what I've figured out so far (which may be wrong), I need to attach my old loading/complete functions to the form so that they'll be fired by the handleRemote function in Rails.js. I'm just not sure how to go about that.
Again, I'm doing this in Prototype. So answers specific to that framework are appreciated.
The answer is the following:
<%= form_for #foo, :remote => true do |f| %>
...
<% end %>
...
<script type='text/javascript'>
$('edit_foo').observe('ajax:before', loading_function());
$('edit_foo').observe('ajax:complete complete_function());
</script>
Try this link. Yes, it is JQuery, but JQuery and Prototype do not differ the way how things work together. Here is a code fragment that adds a new task directly in the index page - and it uses Prototype:
views/tasks/_newform.html.erb:
<%= form_for(#task, :remote => true) do |f| %>
<div>
<%= f.label 'Add a new task: ' %>
<%= f.text_field :name %>
</div>
<div>
<%= f.submit %>
</div>
<% end %>
views/tasks/index.html.erb:
<div id='newform'>
<%= render :partial => "newform", :locals => { :#task => Task.new } %>
</div>
views/tasks/create.js.rjs:
page.insert_html :after, 'tablehead', :partial => #task
page.replace_html 'newform',:partial => "newform", :locals => { :#task => Task.new }
Edit: you need to add "format.js" to our create method of the task controller
For people with a similar issue, it may also help to look at the source code for the remote helpers in the Rails 2.3.x source code.
In my case, I wanted to figure out what to do with the ':update' parameter, as in:
remote_form_for(#obj, :update => "new_obj", :before => "some js code") do |f|
I had to find the update functionality in the remote_function code.
For my specific issue, it looks like it's impossible to get the equivalent of :update with Rails 3 UJS helpers. The rails.js in Rails 3 wraps :remote => true requests with the Ajax.Request(...), whereas the :update function in Rails 2 wraps Ajax requests with Ajax.Updater(...). For people looking to replace the :update feature from Rails 2, I see 2 options:
Switch to jquery-rails, so that you can access the response from the Ajax request, with code like this:
$("#elem").bind("ajax:complete", function(et, e){
$("#results").html(e.responseText);
});
Write your own Prototype based code to grab the form and submit it via ajax, using Ajax.Updater(...) instead of Ajax.Request. Do NOT use :remote => true, since this will attempt to use Ajax.Request.
Side note: I played around with the callback object provided in the ajax:complete event
$('new_obj').observe('ajax:complete', function(request){
console.info(request);
});
The request object doesn't appear to contain the response anywhere in it. It is pretty massive, though, so I could be wrong. Hopefully this will help someone else trying to upgrade from Rails 2 to 3, though.
There's a way to get the response from the Ajax.Request invocation, if you were using remote_form_for with :update option. So, you probably don't need to change it to use Ajax.Updater as a workaround. Basically, you use respone.memo.responseText, in your example it would be something like this:
$('new_obj').observe('ajax:complete', function(response){
console.info(response.memo.responseText);
// Probably you would use it like this:
$('new_obj').update(response.memo.responseText);
});