Controller can not detect ajax requests - ruby

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"?

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

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".

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:
remotipart gem
How to upload multiple files using jQuery

Related

Redirect to another model's index action, and hence view index.erb - Rhomobile

I am developing a Rhomobile application,on submit of a POST method, i am going to my 'Model 1' action, after execution of my action i want to redirect to another model's (Model 2) Index action and list the data.
I am from a Rails background, there i would have used URL, any similar concept exists here or any solution.
i tried, but it didn't worked for me render :controller => :model2, :action => :index
Please Note: I have never used rhodes and all of this information was acquired by simply reading the API documentation and taking a look at the source code.
According to the documentation You should be able to deal with this in a very railsy fashion eg
def some_action
redirect controller: :model2, action: :index
end
Seems the only caveat is if this redirection is to happen in a callback function. In this case the redirection should be handled by the WebView instead e.g.
Rho::WebView.navigate(url_for(controller: :model2 action: :index))
Source for Rho::RhoController#redirect supports these statements in the documentation.
Additionally as you might notice above it appears that Rho has ported a lot of the rails like helpers including url_for

Content negotiation not working with respond_to stanza

Good afternoon Stack Overflow,
def show
# Translating ID to event
#event = Event.find(params[:id])
respond_to do |format|
format.html
format.json { render :json => #event }
end
end
This code should (according to what I read online) generate an html response when the Accept header is set to text/html, and JSON whenever the header is set to application/json. Yet whenever I test this with Postman I always end up getting the representation of the resource that is set first.
In the above code that would be html, even when the accept header is set solely to Json. If I switch them around, I get a json representation, indifferent of what I set the header.
Side question: I'm kinda new to Ruby, and would like to fully understand what the do |x| do_a() do_b() syntax/stanza is. Is this like a Switch statement or more a lambda?
Solution found
My brain just gave out for 2 days, because apparently I was sending Content-Type headers in a GET request, instead of the appropriate Accept Header.
Thx #yoones for trying to help me :)

rails not routing https

The following rails routes.rb file
resources :aggregators, :constraints => { :protocol => "https"} do
collection do
get :confirm
post :send_sms
end
member do
post :confirmed
post :failed
post :cancelled
end
end
is not being called. When a form calls one of these actions,
<%= form_for(#aggregator) do |f| %>
the user gets bounced to the root page of the application. In comparing with and without the constraints, the non-https activity picks up
Started POST [...]
Processing by AggregatorsController#create as HTML
whereas the https version
Started POST [...]
Processing by AggregatorsController#index as HTML
So clearly the routing is missing the create action. (the bouncing back to home is an applicationController method which aplies a policy on the index action) I assumed it would be an integral part of resources. What am I doing wrong? Better yet I only want to invoke https on specific actions and would like to keep the focus on new, create and confirm...

Testing an AJAX POST using Rack::Test - how to pass in data?

I'm using Rack::Test to test my app and need to test the posting of data via AJAX.
My test looks like:
describe 'POST /user/' do
include Rack::Test::Methods
it 'must allow user registration with valid information' do
post '/user', {
username: 'test_reg',
password: 'test_pass',
email: 'test#testreg.co'
}.to_json, {"CONTENT_TYPE" => 'application/json', "HTTP_X_REQUESTED_WITH" => "XMLHttpRequest"}
last_response.must_be :ok?
last_response.body.must_match 'test_reg has been saved'
end
end
But at the server end it's not receiving the POSTed data.
I also tried just passing in the params hash without the to_json but that made no difference.
Any idea how to do this?
Your post endpoint must parse the posted JSON body itself, which I assume you already do. Can you post how your end point works, also the rack-test, rack,ruby and sinatra version numbers? Please mention also how you test whether the server's receiving anything -- namely test mockup may confuse your detection.
post '/user' do
json_data = JSON.parse(request.body.read.to_s)
# or # json_data = JSON.parse(request.env["rack.input"].read)
...
end
Okay so my solution is a little weird and specific to the way I am triggering my JSON request in the first place, namely using jQuery Validation and jQuery Forms plugins on the client end. jQuery Forms doesn't bundle the form fields into a stringified Hash as I'd expected, but sends the form fields via AJAX but as a classic URI encoded params string. So by changing my test to the following, it now works fine.
describe 'POST /user/' do
include Rack::Test::Methods
it 'must allow user registration with valid information' do
fields = {
username: 'test_reg',
password: 'test_pass',
email: 'test#testreg.co'
}
post '/user', fields, {"HTTP_X_REQUESTED_WITH" => "XMLHttpRequest"}
last_response.must_be :ok?
last_response.body.must_match 'test_reg has been saved'
end
end
Of course this is specific to the way the jQuery Forms plugin works and not at all how one would normally go about testing the POSTing of JSON data via AJAX. I hope this helps others.

Sinatra - How to best move variable/parameter between pages

I have a register page with the usual email,name,password ..which is validated in the server's submitted route/page. if it fails then I redirect back but I want to fill the values back in the register page..I can put the register form parameters in the session but it will stay there...is there a page memory(a smaller scope than session) just like session which will be just for the next page and then gone/ which is the best way to implement this.
Thanks
Why don't you just render the registration page from the POST route like this:
post '/register' do
#registration_data = params[:stuff] # store all your registration data
if info_validates # everything validates
redirect './user_home'
else # something fails validation
haml :register # or erb or whatever your template engine is
end
end
Then in your view, have it fill in #registration_data if it exists.
Also, you can clear session data with session.clear.
Ajax validation would be much easier. You just register an onclick event to your form submit button that makes a call to a page that returns a json status code with the error information or 200 for OK. If 200, then submit.

Resources