7

I am using simple_form gem and generating the form I am specifying the remote:true option like this:

<%= simple_form_for @webinar, validate: true, remote:true do |f| %>

So, the output html for the form is the following fragment:

<form accept-charset="UTF-8" action="/webinars" class="simple_form new_webinar" data-remote="true" data-validate="true" enctype="multipart/form-data" id="new_webinar" method="post" novalidate="novalidate"> ... </form>

As I checked, using the standard form_for helper is adding the data-remote='true' to the form when remote:true options is used. And as you can see from the generated html, when I am using the simple_form gem there is such attribute, too.

So, in my controller I have:

def create
  @webinar = Webinar.new(params[:webinar])

  respond_to do |format|
    if @webinar.save
      format.html { redirect_to @webinar, notice: 'Webinar was successfully created.' }
      format.js
      format.json { render json: @webinar, status: :created, location: @webinar }
    else
      format.html { render action: "new" }
      format.json { render json: @webinar.errors, status: :unprocessable_entity }
    end
  end
end

But, always the format.html is used. What i am doing wrong?

EDIT:

I have used logger.debug request.format to check what is the actual format ask for and in the log file it was:

text/html

So, the issue must be in the simple_form generated form - what can be wrong there when we have "data-remote=true"?

gotqn
  • 42,737
  • 46
  • 157
  • 243
  • Do you have `//= require jquery` and `//= require jquery_ujs` in your `application.js`? Do you have a `create.js.erb` file under `/app/assets/view/webinar'? – mccannf May 19 '13 at 20:48
  • Yes, I have all of this in place. I have successfully made ajax request to partials for all actions without create and update. I have also have <%= csrf_meta_tags %> in my application.html.erb file. Actually, the issue is that the controller behaves as the format is html not js. – gotqn May 19 '13 at 20:51
  • You could try to add `:html => { :data => { :type => :json } }` as an option to the simple_form_for... – mccannf May 19 '13 at 21:05
  • @mccannf Not helping either. Any advise how can I check if what type of format is send to my controller? – gotqn May 20 '13 at 20:09
  • 1
    :( You can try a `logger.debug request.format` with a `logger.debug request.headers["Content-Type"]` in your controller. – mccannf May 20 '13 at 20:15
  • This sounds like a javascript issue. Since this feature is unobtrusive, it will degrade to an html request if there is a javascript problem. Things I would check a) do you have an precompiled javascript sitting under your public folder? b) is the console reporting errors when the page is loaded? Try submitting the form via jquery/javascript at the console (perhaps it will report back with errors) – cgat Jun 05 '13 at 08:06
  • How you submiting your form? by subit button or on some jQuery event like on select_box change or keypress etc. – Taimoor Changaiz Jun 06 '13 at 14:05
  • @cgat There is no JavaScript errors both when I am submitting the form with JavaScript and not. What do you mean by a) point - to check which js is in the public folder? – gotqn Jun 06 '13 at 20:38
  • @TaimoorChangaiz I am submitting the form with mouse click on the button. Anyway, I have try to submit the form using the JavaScript and the chrome console but the ajax request was not made. – gotqn Jun 06 '13 at 20:39
  • @gotqn Sometime people will precompile there assets to deploy, which creates a javascript directory under your public folder. If this exists while you are running rails in the development environment, it can cause issues with javascript (usually scripts loading twice). Doesn't seem to be your problem though. – cgat Jun 06 '13 at 21:10

3 Answers3

4

You're confusing format.json|format.html with remote: true. Both are different. The presence of remote: true does not imply format.json.

format.json does not indicate that the URL was invoked via javascript. It only means that the client expects JSON output. i.e. it does not indicate where input came from, it indicates what output is required.

The general use of remote:true is, instead of reloading the page, you submit the form as an Ajax request and then show the response in a JQuery popup or something. But if you want to display the response as a JQuery popup - you need HTML output, not JSON output right?

Some people use remote: true to load HTML content in a popup. Your use case is to do remote: true but you're expecting JSON formatted data. Rails cannot make these decisions for you. It by default sends the request to /webinars and expects that you will handle the HTML response. If you really want JSON response - then customize the URL to which the Ajax request is posted:

simple_form_for @webinar, url: webinar_path(format: :json), .....

If you do the above, now the webinar controller will be called with JSON format.

Overall:

  • remote:true can be used with both format.html and format.json
  • The majority use case in a Rails application is to handle remote: true as a controller request as usual, render a partial HTML template (i.e. the response content alone without the overall page layout/navigation/etc) and send it back as HTML to be displayed in a popup
  • Most people just blanket-handle remote callbacks and display a JQuery popup. So they don't need to write individual code for each remote forms
  • So by default, Rails calls format.html for remote requests
  • If you specifically want format.json, and if you really want to handle the JSON manually on the client, change the URL accordingly. But this is not the majority use case
  • Making an Ajax request does not mean the content-type is JSON. It is a HTML request made using Javascript. e.g. In jquery $.ajax method, check these two options: accept and dataType. If you really want to send Accepts: application/json header, then you have to manually specify that when making the Ajax request (or you need to end the url with .json if its a Rails app).
  • So even if you make a normal Ajax request to /webinars, like $.ajax('/webinars', ...) - it won't go to format.json ! It will still only go to format.html. If you really want a JSON format, then you must say $.ajax('/webinars', { accepts: 'application/json' }), or you must say $.ajax('/webinars.json')

Edit: Minor clarification

Subhas
  • 14,290
  • 1
  • 29
  • 37
  • My initial need was to be able to submit the form using ajax, so if there are any errors or if the data is submitted correctly, to refresh only part of the page - now it is refreshing the whole page. I though that adding remote:true will make my the controller to use the *.js partial. For links in my application this is working OK, but I guess for submitting form not? If so, does this mean that in order to refresh only part of my page when I have form I need to use JSON format only? – gotqn Jun 08 '13 at 09:47
  • After making an Ajax request using `remote: true`, you now have two ways to refresh part of your page: (1) Return a JSON from the URL, parse it in the browser and update your page using javascript/jquery, *OR* (2) Return a partial template (small snippet of HTML without entire web page layout) from the URL, show a jquery popup. If you need (1) - you will end up writing more javascript code, and similarly in the URL you need to specify the form's URL as `/webinars.json`. If you need (2) - you can say the form's URL as `/webinars`. – Subhas Jun 08 '13 at 11:49
  • Right now, it looks like you want to do (1) (return JSON), and you want to handle the JSON manually in the browser. Then you need to specify the simple_form URL as `/webinars.json` – Subhas Jun 08 '13 at 11:50
  • Thanks, what I want is actually (2) - to render a partial template. I am going to continue searching why it is not using my create.js.erb – gotqn Jun 08 '13 at 11:55
  • Hi @gotqn, since the request format is HTML - rails will by default render `.html.erb`. Only when the request format is JSON, rails will render `.js.erb`. If you want the `render` function to explicitly render that `*.js.erb` template, then please refer this answer: http://stackoverflow.com/questions/339130/how-do-i-render-a-partial-of-a-different-format-in-rails – Subhas Jun 08 '13 at 11:59
  • HI @RDX, When I am using /webinars.json the controller is not using my create.js.erb template either. Is there a way to change the requested format from HTML to JS? – gotqn Jun 08 '13 at 12:10
  • `*.js.erb` is called only when format is `js` - and not `json`! In the [Rails example](http://edgeguides.rubyonrails.org/working_with_javascript_in_rails.html#a-simple-example), you would see that they're using the `create.js.erb` template only for `js` requests. For `json` they have a different format block. Similarly you have to use `format:js` for the specific `.js.erb` template... – Subhas Jun 08 '13 at 12:15
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/31448/discussion-between-gotqn-and-rdx) – gotqn Jun 08 '13 at 12:16
2

It seems like you are not directly requesting a JSON formatted document in the generated form action. Perhaps one option is to set :format to json in your routes file using this technique: http://guides.rubyonrails.org/routing.html#defining-defaults

You can also define other defaults in a route by supplying a hash for the :defaults option. This even applies to parameters that you do not specify as dynamic segments. For example:

match 'photos/:id' => 'photos#show', :defaults => { :format => 'jpg' }

Rails would match photos/12 to the show action of PhotosController, and set params[:format] to "jpg".

Community
  • 1
  • 1
Rashi Abramson
  • 1,127
  • 8
  • 16
2

I can not believe that I have lost so much time in trying to understand why the simple_form is not working as expected.

Finally, it appears that I have done everything in the right way and the issue was caused because:

AJAX can not be used for file uploads.

In order to solve my problem I simply have to add the following gem into my Gemfile and run the bundle install command:

gem 'remotipart', '~> 1.0'

Then add the following line in my application.js file:

//= require jquery.remotipart

More information about:

  1. remotipart gem
  2. How to upload multiple files using jQuery
gotqn
  • 42,737
  • 46
  • 157
  • 243