Is there a way to submit ajax/json requests with simple_form for Rails

17,225

Solution 1

Figured it out. You just need to add the this:

:input_html => {"data-remote" => true, "data-url" => "/yoururl", "data-type" => :json}

Solution 2

It is better to write it like this:

= simple_form_for sample_result, url: reject_sample_result_path(sample_result), method: :post, remote: true, input_html: {multipart: true} do |f|

When you explicitly declare data-url it will still first do the default route calculation, which in my case failed because the default routes did not exist (and should not exist --since I am overruling the url). When you declare just url it will just take the given url instead.

Solution 3

I wanted to post a related follow up, because I had some difficulty figuring out how to implement the callback for this. I found this article to be very helpful: http://www.simonecarletti.com/blog/2010/06/unobtrusive-javascript-in-rails-3/

The secret is either to add an HTML5 data attribute, e.g. data-complete or (better) bind the ajax:complete or ajax:success callbacks provided by Rails to your form (see 4. Remote JavaScript Callbacks in article linked above):

From the article:

jQuery(function($) {
  // create a convenient toggleLoading function
  var toggleLoading = function() { $("#loading").toggle() };

  $("#tool-form")
    .bind("ajax:loading",  toggleLoading)
    .bind("ajax:complete", toggleLoading)
    .bind("ajax:success", function(event, data, status, xhr) {
      $("#response").html(data);
    });
});

CoffeeScript example:

$("#new_post").on("ajax:success", (e, data, status, xhr)->
  console.log data
)

Solution 4

It seems the valid way to do this now is:

:remote => true, :html => { :data => { :url => '/yoururl', :type => :json } }

which may look a little better with ruby 1.9 hash syntax as:

remote: true, html: { data: { url: '/yoururl', type: :json } }

https://github.com/plataformatec/simple_form/wiki/HTML5-Attributes

Solution 5

The simplest way to do this that I have found, and for a fuller example, is:

In your view:

<%= simple_form_for :my_object, url: my_objects_path(format: :json), remote: true do |f| %>
  <%= f.error_notification %>
  <%= f.input :an_attribute %>
  <%= f.submit %>
<% end %>

and in your controller:

def create
  @my_object = MyObject.new(my_object_params)
  if @my_object.save
    respond_to do |format|
      format.html { redirect_to @my_object, notice: "Saved" }
      format.json { render json: @my_object, location: my_object_url(@object), status: :created }
    end
  else
    respond_to do |format|
      format.html { render :edit }
      format.json {render json: @my_object, status: :unprocessable_entity }
    end
  end
end

In Rails 5 it's even easier on the controller with the Jbuilder installed to create simple json hashes but this should work there too.

Share:
17,225
Nathan
Author by

Nathan

Updated on July 27, 2022

Comments

  • Nathan
    Nathan almost 2 years

    With the standard Rails form_for, I was able to pass ajax requests though select and collection_select helpers as such:

    <%= address.collection_select :country, @countries, :id, :name, {:include_blank => false}, "data-remote" => true, "data-url" => "/ajax/states", "data-type" => :json  %>
    

    I can't seem to figure out how to do this with simple_form

  • Matt
    Matt about 11 years
    It should be :input_html => instead of :html =>
  • Blake
    Blake about 11 years
    thanks. one follow up question - how did you set your javascript callback for this?
  • SteveO7
    SteveO7 about 10 years
    I'm confused on how to implement this. What does the full line of code look like? f.input :my_field :collection => ????
  • Aleks
    Aleks almost 9 years
    For some new browsers (2015 :) ) you will need to add format: :json in order for the form to work properly, like: <%= simple_form_for(@object, html: { class: 'your_class', id: "#new'}}, url: your_resource_path(@object, format: :json), remote: true, authenticity_token: true, data: { type: 'json' }) do |f| %> # Code <%end%>
  • Nathan
    Nathan almost 9 years
    I'm pretty sure the "data-remote" => true sends a js request. If you need to specify a json request, sure you can do what you're suggesting. But that may not be desired, nor is it required I don't think.