We are upgrading a Rails 6 app to Rails 7 and cannot submit ajax requests. They just do normal form submits and the page reloads. We are doing this with javascript.
The result of the form submit is loaded into a different div on the page by javascript inside the js.erb.
Here is the form:
<%= form_with model: EmailTemplate.new, url: preview_send_now_email_templates_path,
html: { id: 'emailPreviewForm' },
format: :js, method: :post, remote: true, data: { turbo: false },
authenticity_token: true do |f| %>
<input type="hidden" name="email_template_id" value="1234">
<input type="hidden" name="order_id" value="5678">
<% end %>
On the page that generates HTML that looks like this:
<form data-turbo="false" id="emailPreviewForm" action="/email_templates/preview_send_now" accept-charset="UTF-8" method="post">
<input type="hidden" name="authenticity_token" value="yaddayadda" autocomplete="off" />
<input type="hidden" name="email_template_id" value="1234">
<input type="hidden" name="order_id" value="5678">
</form>
And we submit it by Javascript like this:
document.getElementById('emailPreviewForm').submit();
In a brand new Rails 7 app this works - it submits via Ajax and doesn't do a page reload. Oddly, it doesn't see the format as javascript, which makes me think there is some sort of conflict going on in the writing out of these tags.
This could very well be me not understanding some significant changes in Rails 7, but, it seems to me that it shouldn't cause such a significant thing to stop working.
UPDATE
At mike-a's suggestion I added:
config.action_view.form_with_generates_remote_forms = true
To my application.rb. To be honest, this did not seem to change anything. Adding the local: false was the thing that added remote: true into the form definition.
I also changed the form to this:
<%= form_with model: EmailTemplate.new,
url: preview_send_now_email_templates_path(format: :js),
html: { id: 'emailPreviewForm2' },
method: :post, local: false,
authenticity_token: true do |f| %>
<input type="hidden" name="email_template_id" value="1234">
<input type="hidden" name="order_id" value="5678">
<% end %>
Which gave me:
<form id="emailPreviewForm2" action="/email_templates/preview_send_now.js" accept-charset="UTF-8" data-remote="true" method="post">
<input type="hidden" name="authenticity_token" value="yaddayadda" autocomplete="off" />
<input type="hidden" name="email_template_id" value="1234">
<input type="hidden" name="order_id" value="5678">
</form>
Adding the format: :js to the path at least fixed that. But otherwise, doing document.getElementById('emailPreviewForm2').submit(); still simply submits and loads the resulting rendered js.erb file into the browser.
It is not remote.
I do have turbo loaded (because I am slowly converting things to hotwire and turbo). Actually, this situation is forcing me to convert a lot more than I wanted to!
Can you try replacing remote: true with local: false? I don't see a remote option for form_with in the Rails docs. You may also want to read about that option in the docs as the default changed in Rails 6.1. https://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html#method-i-form_with
So if you were upgrading from Rails 6.0, and aren't setting config.action_view.form_with_generates_remote_forms in your configuration, the default could have changed on you.
Another thought, if the above doesn't change anything: in Rails 6 the remote forms functionality was provided by ujs (unobtrusive javascript). I believe in Rails 7 ujs is gone and something else is used (Turbo?). Perhaps your fresh Rails 7 project works because it brings in Turbo (or whatever new js library is doing the work), but in your upgraded Rails project you aren't bringing that new dependency in. Sorry for being vague... I don't know the new frontend changes very well. I'm just throwing out things to look into.
Related
To be more specific, I am creating a character sheet for Pf2e for a project. I have a 'Character Schema' which includes all of my various inputs (normal text/number, checkboxes, and textarea inputs). I can get it to work with 1 input, but I'm sure there is an easier way than writing the following:
<% if(characterData.length === 1){ %>
<input class="larger-input" id="id1" type="text" placeholder="" name="ancestry" value="
<%= characterData[0].ancestry %>">
<% } else { %>
<input class="larger-input" id="id1" type="text" placeholder="" name="ancestry" value="">
<% } %>
Basically, if the user has never "saved" data before I was getting an ejs error. So the previous code says 'if there is data, show it, else show an empty field'. Im really new at all this and I know some other frameworks help, but I am doing this with strictly vanilla JS, Node(Express + mongoose) and EJS.
The code can be found here https://github.com/TartCodes/main-character-manager
First post on here, sorry for the length! Any help is appreciated!
I'm trying to render a js alert directly after a user clicks on a submit.
Here's what I have and what I've tried:
That's my erb file.
<form action="/welcome/subscribe">
<div>
<div id="bottomm">
<input id="bottom" type="text" name="email" placeholder="Adresse mail" />
</div>
<div>
<input type="submit" value="Ok"/>
</div>
</div>
</form>
Here's the subscribe method in my controller:
def subscribe
#test = Test.new
#test.email = params['email']
#test.save
binding.pry
render js: "alert('test)";
end
But I get this error:
Security warning: an embedded <script> tag on another site requested protected JavaScript. If you know what you're doing, go ahead and disable forgery protection on this action to permit cross-origin JavaScript embedding.
Any idea? :/
edit:
By adding theses 2 lines I can now avoid the warning:
protect_from_forgery with: :exception
skip_before_action :verify_authenticity_token
But now it's redirecting me on a blank page with just written on it:
alert('test')
You are missing data-remote attribute in your form, just add it:
<form action="/welcome/subscribe" date-remote="true">
<div>
<div id="bottomm">
<input id="bottom" type="text" name="email" placeholder="Adresse mail" />
</div>
<div>
<input type="submit" value="Ok"/>
</div>
</div>
</form>
Update
Btw, from the given error, you may add protect_from_forgery to your application controller:
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
protect_from_forgery with: :exception
# Other code
end
For more detail, please read this documentation
You need to specify that your form will be submitted asynchronously (IE without a full page refresh). When using form_for to generate your form, you would include :remote => true. Since you are typing out your full form you need to do this:
<form action="/welcome/subscribe" date-remote="true">
#...
I am developing my first Ruby on Rails real application, and I want to achieve a very simple task:
I have an input in my view, whose value represents a field of one of my models. I want to, via ajax, update this field in my model when the user changes the value of the input.
How can I do that?
Thanks a lot
html code:
Product#View
...
Stock: <input type="text" name="p[stock]" placeholder="Stock" value="<%= #product.stock %>" /><br>
...
controller:
def view
#product = Product.find(params[:id])
end
I have been given a task by my boss who still likes things the old way... have a HTML page/view and submitting a form to a PHP page server side. We have introduced AngularJS to his app and he has the following code in his page:
<form name="rForm" id="rForm" action="demo_form.php" method="post">
<input type="hidden" name="quantity" id="reservationQuantity" ng-value="selectedQuantity"/>
<input type="hidden" name="date" id="reservationDate" ng-value="selectedDate"/>
<input type="hidden" name="time" id="reservationTime" ng-value="selectedTime"/>
<input type="hidden" name="mId" id="mID" value="{{ $merchant->id }}" ng-value="mId"/>
</form>
<button>Go to next page...</button>
Now he wishes for us to have a link or button to submit this form which is outside the form, I believe that we should control all of this is a controller with all post functionality being handled by an injected / separate $http service. He doesn't believe me and says he knows best and I should just handle submitting the form like so
<button onclick="$('#reservationForm').submit();">Go to next page...</button>
I don't like this... however he pays the wages. Is there some way I can submit the form/page from my Angular controller and remove all that horrible jQuery code? Something like this (this won't work, I am just using this for visual purposes)
<button ng-click="ng-submit()">Go to next page...</button>
... and am I right saying that his method is bad practice and if we are going to submit to the server by pushing the page there's no point in us using an MVC framework.
Yes you can submit form through your Angular Controller. For this all you have to do is to call controller function in your ng-click like this:
<button ng-click="submit()">Go to next page...</button>
where submit() is your controller function. One more thing you need to assign ng-model to all form fields to access them in controller.
As a college student at QANTM I regularly use its portal system to check information that is relevant to my study. However, the site uses a specific system that makes it impossible to view on small resolutions, such as mobile browsers.
I'm developing a small personal application that should allow me to view the contents of the site in my own formatted view. However, I'm having some issues executing JavaScript to submit credentials.
<form id="userslogin" method="post" action="javascript: saePortal.users.submitLogin();" onsubmit="return false" class="x-hidden">
<input type="text" id="username" name="username" />
<input type="password" id="password" name="password" />
<button type="submit" id="submit" value="Login" class="x-hidden" /></button>
</form>
This is basically the form structure of the portal and I am successfully able to alter the username and password field with my desired contents using
document.forms[0].username.value = 'text';
However I am unable to submit the results. I have done some searching online and it's not a simple matter of submitting the form. It refreshes the page.
document.forms[0].submit();
I've also tried non-standard compliant code such as document.forms[0].submit.click(); and many variants of this, as well as using getElementById with no luck.
The site in question https://portal.qantm.com.au/. I'm unsure if this is a form of protection that's built into the site or if I'm simply using the wrong syntax.
You could use JavaScript FormData-class if your browser supports it.
var fd = new FormData();
fd.append("username", username);
fd.append("password", password);
Then you could post this using jQuery or something.
$.ajax({
url: portalurl,
type: 'POST',
data: fd,
contentType: false,
processData: false,
success: function(data){
console.log(data);
}
});
Change attribute onsubmit="return true" in form tag.