I have a rails application in which I need to create some input form where user could enter regular expression. This regex needed to be passed to my method check_site(url, regex) that will return true or false depends on regex found on the page.
I've tried to create a 'link_to':
link_to 'Search', check(item.name, #pattern)
In this case method "check" is called not with button pressed but with page loading.
Do I need to use JS+AJAX? How to?
Crash course on getting AJAX/JS set up with your Rails form:
Ensure correct javascript is called in your page <head>: JQuery + application.js (Jquery-compatible version, of course!)
Change your link to:
link_to 'Search', check_item_path(:name=>item.name, :id=>#pattern, :var=>var, etc.), :remote => true
In items_controller:
def check
...your regex...
respond_to do |format|
format.html { redirect_to ...(wherever you'd like if no .js) }
format.js
end
end
Create a file called check.js.erb in the corresponding views folder and enter the javascript you'd like to update the page / confirm the form's successful submission / return results from your search, etc.
$(document).ready( function() {
$("#result").html(" <%= #item.result == true ? "true" : "false" %> ");
});
No method error: check_item_path
This means Rails is not recognizing the route to that controller action. Run rake routes in console and see if anything corresponds to the items controller, check_item action. If not, add:
match 'items/check_item'
to your routes file. Then run rake routes again and you should see check_item appear somewhere - if it does, you can use check_item_path again.
Related
I have inherited a Rails code base that I do not fully understand. We have a requirement to, when the user hits Submit, render ON THAT PAGE the set of validation failures the user put into the form. I cannot redirect to any other page - we must remain on the page which contains the form upon which they put the invalid input.
Here is my method
def tpr_bulk_update
updated, date_died = update_tprs #it returns 0,0 when there are validation fails
if updated == 0 && date_died == 0
flash.now[:notice] = 'A bunch of errors occurred'
#Here I need to refresh the page. I do not especially want to redirect.
#I want this to perform exactly the same as me hitting the refresh button on my browser.
#The initial form loaded via a very complicated codebase that I do not understand exactly.
#I do have available to me the params from the initial call - but it seems to me hitting refresh on
#the browser implicitly handles repassing to this method with the SAME PARAMS I CAME IN WITH....
#AND it shows my flash.now. So then, I want to refresh the page the same mechanism the browser uses,
#because this is what demonstrably meets my requirement
elsif !date_died
redirect_to tprs_index_vod_assets_path
else
flash[:notice] = "One or more TPR assets were not given valid future dates, so those invalid dates did not save".html_safe
redirect_to tprs_index_vod_assets_path
end
end
The issue is I see no way to do this. Perhaps the browser invoking refresh uses javascript that is impossible to inline in my rails controller?
redirect_to :back
fails on account that the set of params I came in with are not populated - it explodes.
respond_to do |format|
format.js {render inline: "location.reload();" }
end
My method does not output javascript, and neither will it ever output javascript - that is a requirement for the system.
I need whatever is equivalent to the refresh operation my browser (Chrome) performs when I press "Refresh". I want that to happen right after I set my flash.now message. How can I capture what Chrome/what hitting refresh actually does? And how can I perform it within my controller?
This is exactly what AJAX was designed for. By sending an asyncronous request you can send data to the server without reloading the page and update the page with the response. In Rails you can use Server Side Concerns to simply replace a chunk of contents with a rendered view.
Since you don't actually have an example of the form or controller this is a simplefied example that demonstrates the concept:
class ThingsController < ApplicationController
def new
#thing = Thing.new
end
def create
#thing = Thing.new(thing_params)
respond_to do |format|
if #thing.save
format.js
else
format.js { render :new }
end
end
end
end
end
# things/_form.html.erb
# remote: true is the default - its just added for extra clarity here
<%= form_with(model: #thing, remote: true, id: 'my-special-form') do |form| %>
<% if #thing.errors %>
# .. display the errors
<% end %>
# ...
<% end %>
# things/new.html.erb
<%= render partial: 'form' %>
// things/new.js.erb
// Since we want to extract the children of the form element
// we use DOMParser to create a fragment
const node = new DOMParser().parseFromString(
"<%= j render(partial: 'form') %>", // rails renders the template
"text/html"
);
// Find form on page and replace its contents
document.getElementById('my-special-form').innerHTML = node.querySelector('form').innerHTML;
// #todo set flash message
// things/create.js.erb
window.location = "<%= thing_path(#thing) %>";
The way that this works is that Rails UJS listens for submit events on any element with the data-remote attribute. Instead of the normal submit it will send an XHR request with the Content-Type: application/javascript header.
After rails is finished rendering and reponding with your js.erb view it is sent back to the client and Rails UJS takes the response and evals it by popping it into a script tag.
I have a form in a partial _donation_form.html.haml which is rendered as a modal. I am trying to do the following:
If the record can be saved, redirect to a different page
Else render the modal with validation error messages.
Everything works except that when the record is invalid, redirection to a different page does not work.
I have the following in _donation_form.html.haml which is rendered as a modal.
= bootstrap4_form_for([:admin, donation], remote: true, html: { multipart: true, id: 'manual_donations', autocomplete: 'nope'}) do |f|
# form with submit_button which calls `create` action of `donations_controller.rb`
This is my new.js.erb which renders the above modal:
$('#newDonation').modal('hide');
$('#newDonation, .modal-backdrop').remove();
$('body').append("<%= j render partial: 'donation_modal' %>");
$('#newDonation').modal('show')
I added remote: true in _donation_form.html.haml as when the validation fails I want to render new.js.erb.
Following is donations_controller.rb:
def index; end
def new
donation.cause_id = cause.id if entity.causes.count == 1
donation.event_id = params[:event_id]
end
def create
# some code
begin
ActiveRecord::Base.transaction do
donation.recorded_offline!
respond_with(:admin, donation, :location => admin_donations_path)
end
rescue ActiveRecord::RecordInvalid
render :new
end
end
When I click on submit button of the modal with a valid record, page does not redirect and I get the following message on console:
Processing by Admin::DonationsController#index as JS
-----------
No template found for Admin::DonationsController#index, rendering head :no_content
I have the view index.html.haml under app/views/admin/donations/. When I remove remote: true from _donation_form.html.haml, redirection works just fine. However, in that case rendering new.js.erb with validation error messages does not work. I am not really sure how to tackle this situation.
I am trying to establish a dynamic form on a contact's page. I would like on this page to be a link that says "add an email address" and then when I click on it, a form appears to enter email address.
So I used a link_to with remote true :
= link_to "Add an email", add_email_path, id:'link-remote-link', remote: true
In my controller i specified :
def add_email
render layout: false
end
But when I receive my response with listening on ajax:sucess, layout is still their in the variable. But I just want the form add_email.html.haml
In order to try to know if the code in my controller was executed, I tryed to put a creation of an object in it. Fact is that it was never created.
Never the less, rails console writes "Processing by ContactsController#add_email as JS
"
So...why is it not executed ?
Thank you :)
Layout
We set the layout in the application_controller to manage the ajax responses:
#app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
layout Proc.new { |controller| !controller.request.xhr? }
end
You may wish to try this - to see if it's the call in your controller which is rendering the layout.
Personally, I think your layout: false call is being overridden with some other element / part of your controller. I'd recommend checking to make sure this is the case
--
Controller
As you've stated, the case may be that your controller isn't being called, or processed correctly.
This could be caused by a number of issues, most notably from having incorrect routes, or some other dependency preventing the method from firing properly.
To clarify, I would make sure I have the following set up:
#config/routes.rb
resources :contacts do
get :add_email, on: :collection
end
#app/controllers/contacts_controller.rb
class ContactsController < ApplicationController
def add_email
...
end
end
I have a pretty standard Rails HAML new object form that does the usual stuff and ends with:
= f.submit "Add scenario"
This works perfectly, and the scenarios_controller.rb is also a straightforward:
def create
...create scenario...
redirect_to scenarios_path
end
However, I have also developed a wizard-type form that needs to do some JavaScript on pressing my button:
= f.submit "Add scenario", :onclick => "return validateForm()"
In my CoffeeScript, I collect up all the information and finish up with:
$.post(
url
data
(data, textStatus, jqXHR) ->
# How do I follow the redirect?
return false
My url and data are correct as the above controller works correctly and creates my object, but my page doesn't redirect to scenarios_path. I think I should be doing something with the post result, but searching around the web I cannot find out what, and examining the returned fields in Chrome's debugger doesn't suggest anything. The only suggestion I saw was to use data.redirect, but such a field doesn't exist, although jqXHR.responseText seems to contain the page I want to redirect to.
I'd treat the HTML call to Scenario#create and the JS call to Scenario#create differently, using a respond_to block.
In your scenarios_controller.rb file:
def create
# create your object
respond_to do |format|
format.html do
redirect_to scenarios_path
end
format.js
end
end
In views/layouts/scenarios/create.js.erb, then put something like:
window.location.replace("<%= scenarios_path %>");
When you call Scenario#create with JS, the create.js.erb file gets rendered and forces the redirect. When you call Scenario#create with HTML, the redirect_to call happens as usual.
Lately i have run into a few applications that are using js.erb and i am not really sure how to use it ...here is the code below. Can someone help me understand how this works?
in the routes.rb file
map.resources :player_emails
my controller player_emails_controller.rb in the create action
def create
#player_email = PlayerEmail.create(params[:player_email])
if #player_email.save
#response_txt = "The player has been emailed."
PlayerEmailsMailer.deliver_pattern_email(#something, #player_email, request.host_with_port)
#error = false
else
#error = true
#response_txt = "Please make sure you entered your name and a valid email address."
end
end
then i have the file player_emails/create.js.erb
$('#player_email_ind').hide();
$('#player_email_submit').show();
$('#player_response_msg').html("<%= escape_javascript #response_txt %>").fadeIn();
<% unless #error %>
$('#player_email_form')[0].reset();
<% end %>
i know what the jquery is going but i dont know how this is doing the ajax call. Does it just automatically do an ajax call when there is a js.erb...can someone explain the way this works and why i dont need a respond_to in the controller action telling it this is format.js
If a js (ajax) request is made it will respond by rendering the js.erb file and viceversa.
This is the default behaviour that is being performed:
respond_to do |format|
format.js{
render :template => 'create.js.erb'
}
format.html{
render :template => 'create.html.erb'
}
end
When the form is submitted, it does a POST to /player_emails. The resource declaration in routes.rb ensures the request is handled by PlayerEmailsController#create.
The controller is responsible for handling each format it receives. In the case of an AJAX call, the format is 'js', and is set by explicitly adding the format string to the end of the URL (/player_emails.js) or (more likely) by deducing the format from the request header.
In your case, the create action does not expect anything other than AJAX, so it takes a shortcut and omits the respond_to and format blocks. The controller has already figured out that the format is 'js', so when create is complete it takes the default action of rendering the appropriate template for the format (create.js.erb).
Does your form submit button have a :remote => true on it? If so, there might be some JavaScript in rails.js or application.js that automatically submits via AJAX. Bottom line is, there has to be some JavaScript somewhere that is making an AJAX call and asking for a js or JSON response, otherwise it would be an html request.
As for why you don't need a respond_to block, I'm not entirely sure. Maybe since the call is always being made by AJAX and there is a js.erb template available, it just does its thing without complaining. Is there an html.erb template at all? If not, try doing a regular form submit and see if it complains.