using both :url and :function on observe_form - ruby-on-rails

Is there a way to generate both a Javascript function call and an Ajax call in the same observe_form tag? For example, something like this:
<%= observe_form 'user_filter_form', :url => { :action => :process }, :function => :fix_fields %>
Thanks!!

Your best bet here is to dig into the actual JavaScript instead of relying on the helpers. The helpers can only get you so far. What you want is something along these lines:
<script type="text/javascript">
new Form.EventObserver('user_filter_form', function(element, value){
fix_fields();
new Ajax.Request("/YOUR_CONTROLLER/process");
}
</script>
However, if you really want to rely on the Rails helpers you can do something like:
<%= observe_form 'user_filter_form', :function => "fix_fields(); #{remote_function(:url => { :action => :process })}" %>

Use :before or :after options instead of :function, depending on whether you want your function called before of after the Ajax request.
See documentation of link_to_remote helper for common options that can be passed to all the Ajax helpers like observe_form

Related

quotation havoc while posting data in html attribute

I want to post some data as an html attribute. Suppose there is a rails variable
#fields = [{:name => "id", :type => :integer}]
I want to post in the page for use with jquery's .data(). So in the .html.erb I have
<%= form_tag( {:action => 'whatever'}, {... , :"data-fields" => h(#fields.to_json)}) %>
But while rendering, the quotations in string [{"name":"id","type":"integer"}] mess up the other attributes because Rails form_tag uses double quotes to enclose the whole json string in double quotes. How do I post json with strings as an attribute from Rails?
Have you tried the following?
<%= form_tag { :action => "whatever" }, { :data => { :fields => h(#fields.to_json) } } %>
Have you tried escape_javascript ? Although it has known downsides, it is not exactly for escaping JSON, and I am not sure escaped quotes will work in HTML attributes.
There is an episode on railscasts addressing your situation using a serializer. The point is that the serializer replaces double quotes with $quot; The serialuzer also gives you the ability to select which attributes to serialize and include associations.
After some trial and error this is what works.
Server side:
<% #fields = [{:name => "id", :type => :integer}] %>
<%= form_tag( '/posts/new', {id:'example',:data => { :fields=>#fields}}) %>
Generated HTML:
<form accept-charset="UTF-8" action="/posts/new" data-fields="[{"name":"id","type":"integer"}]" id="example" method="post">
Javascript wiht JQuery's data method
fields = $('#example').attr('data-fields')
I'm using rails 2.3.8 and jquery-rails 2.2.1
Here is how I side-stepped the problem:
In the form tag, I did :"data-fields" => #fields.to_json.gsub('"',"'").
This produces HTML of this sort:
"data-fields"="[{'name':'id','type':'integer'}]"
And then, in the JS, I retrieve it like this:
$.parseJSON($('form').data('fields').replace(/'/g,'"'))

What is the Rails convention for sending form data to a URL dependent on form value?

I would like a form submitted at the url
/index/fruit
to submit the form data to
/index/:identifier
where :identifier is determined by a value of the form
What is the rails convention in this instance?
Is there a way to achieve this without a controller level redirect or javascript-updating the submit URL?
routes.rb
match 'smasher(/:action(/:id))', :controller => "customcontroller", :as => :smasher, :defaults => { :action => :index, :id => :fruit }
index.html.erb
<%= semantic_form_for :d, :url => smasher_path, :html => { :method => :get } do |f| %>
... form data ...
<%= f.input :identifier, :as => :hidden %>
<% end %>
My current implementation is similar to this answer
There's isn't really a "convention" for this, but rather one of those things where there's more than one way to do it.
One way that you could do it is still send the form to one and only one action within the controller, but then delegate in the controller which action to go to, like this:
def smasher
if params[:identifier] == 'this'
smash_this!
else
smash_that!
end
end
def smash_this!
# code goes here
end
def smash_that!
# code goes here
end
Heres the javascript version (though technically its all on an erb html template), if you're feeling up to it.
<%= f.input :identifier, :as => :hidden, :onchange => "$(this).setAction()" %>
<script>
// While you can this script block here within your erb template
// but best practice says you should have it included somehow within `<head></head>`
$(function() {
//create a method on the Jquery Object to adjust the action of the form
$.fn.setAction = function() {
var form = $(this).parents('form').first();
var action = form.attr('action')
form.attr('action', action.substr( 0, action.lastIndexOf('/')+1 ) + $(this).val());
}
});
</script>
Heres the pure javascript version:
$(function() {
//create a method on the Jquery Object to adjust the action of the form
$.fn.setAction = function() {
var form = $(this).parents('form').first();
var action = form.attr('action')
form.attr('action', action.substr( 0, action.lastIndexOf('/')+1 ) + $(this).val());
}
//we gotta bind the onchange here
$('input[name="identifier"]').change($.fn.setAction);
});

Ruby hash map with key that contains '-'

How can I add hash map element with a key that contains "-"?
Like this:
<%= button_to_function 'Cancel','cancelRemove("cancelEmail")', :data-dismiss=>'modal', :class=>'btn' %>
I get an error:
undefined local variable or method 'dismiss' for #<ActionView::Base:0x3482fed>
While :'data-dismiss' works, with data attributes you can also do
:data => { :dismiss => 'modal' }
Additional data-prefixed html attributes can be included in the same hash. So for example on another link you might do:
:data => { :remote => true, :method => 'delete' }
which would add to the link the html attributes data-remote="true" data-method="delete".
While the hash syntax is less compact for a single attribute, it's nice when you've got more than one html5 data attribute. And it's arguably a bit more rails-ish.
Just rename it to:
<%= button_to_function 'Cancel','cancelRemove("cancelEmail")', :'data-dismiss'=>'modal', :class=>'btn' %>

Make a Select Box that Calls a Method

I have a rails app with working reports that have tags. In the Report/Index.html.erb I want the user to be able to sort the reports by selecting a tag. They may only select one tag at a time so I feel that a select box would work best. I currently have this:
<%= select("preferences", :tag_with,
["Politics", "Technology", "Entertainment", "Sports", "Science", "Crime",
"Business", "Social", "Nature", "Other"], :prompt => "Filter Feed by:" )%>
I have a working preferences controller with a method call tag_with that updates the current tag. This code, however, only generates the select box. I want it to be that when the user selects one of the tags, it calls the tag_with method from the preferences controller.
I generated a series of link_to lines that complete the task, however I would really like a select box.
<%= link_to "Politics", :action => "tag_with", :tag => "Politics", :controller =>"preferences" %>
<%= link_to "Entertainment", :action => "tag_with", :tag => "Entertainment", :controller =>"preferences" %>
<%= link_to "Science", :action => "tag_with", :tag => "Science", :controller =>"preferences" %>
<%= link_to "Technology", :action => "tag_with", :tag => "Technology", :controller =>"preferences" %>
And so on for each tag. This works fine but is bulky and undesirable. Is there a way to do the same thing through a select box?
In your reports.js.coffee file, or whatever other js file you want.
jQuery ->
$('select#preferences').change ->
$.get 'preferences/tag_with',{ term: $('option:selected', this). val() }
Or, if you want to use regular javascript:
$(function(){
$('select#preferences').change( function() {
$.get('preferences/tag_with',{term: $('option:selected',this).val()});
});
});
A link is a GET request. The jQuery .change() method fires whenever someone makes a change. The $.get method sends a GET request to a URL and can pass data (the second argument). This data becomes your params hash, so in the example above you would get:
params[:term] #=> the value attribute of whatever option was selected by the user
See the jQuery docs on .change() and $.get() for more help.
Update
For this to refresh the page, the easiest thing would be to extract the table that you want changed into a partial, let's assume it's called _report.html.erb. The partial should look something like this:
<div id="report">
<%= render #report %>
</div>
*Note: render #report is just short for render :partial => 'report'. See http://guides.rubyonrails.org/layouts_and_rendering.html*
In your preferences controller, tag_with option you should be sure to set the #report object (or whatever else is delivering the data to your partial).
Then you should make a file called views/preferences/tag_with.js.erb and put something like this in it:
$('div#report').html('<%= escape_javascript( render #report ) %>');
This will update the report container with the new content.

Ruby on Rails: form_for works, but remote_form_for doesn't

<% remote_form_for(#media, :url => url_for(:controller => :attachments,
:action => :add_from_disk, :object_id => #object),
:html => { :multipart => true, :id => 'new_media', :onsubmit=>'unsaved_changes = false' } ) do |f| %>
but if I change the remote_form_for to form_for, I don't get this error:
ActiveRecord::RecordInvalid (Validation failed: Document file name must be set.):
Why would it work with form_for, but not the AJAX version?
You can't upload a file using AJAX.... You'll need to implement a flash uploader to send files in the background. It's not pretty, but Uploadify is pretty cool
Recommend keeping file uploading as regular form for.
Or you can use the jQuery form plugin, which works great. In this case you'd do a normal form_for, and inside of your javascript file (once you've included jquery and the jQForm lib in your html) you'd do something like this:
$(function() {
$("#myFormDomID").ajaxForm({ iFrame : true });
});

Resources