问题
I am basic developer of Rails, Not some professional !
I am trying to auto save the rails form after some interval using ajax Dynamically. Actually The real need is that when the first time ajax function executes it inserts the object in the database and afterwards it updates that object. I tried this approach on simple object without any Associations and it works, but right now The requirement is quite different.
The model has has_many associations. These Associations is being managed with Rails Cocoon Gem The approach I used before is when ajax call returns success I update the param and then I checked it in the controller and send it to update action rather than create, but now If I used this approach I can get the Model but can't its associations, so all the associated objects keep inserting in the database.
So, I changed my approach, when first time my ajax call hits the create action I send it to the JS file where I replace and render the new form with the edit form of the newly created object. But this time instead of the edit form script is execute, it keeps running the new form script ?
Is someone Notify my where I did something wrong? or Is there any Better Approach also for the Performance Issue of the Application
There is Some Code to Elaborate what is going on !
New Form for the Object
<div id="dynamic_form">
<% quote = @quote %>
<div class="container form-prquote">
<%= form_with(model: quote, local: true, multipart: true, id: "new_quote") do |form| %>
......... All Form Fields
.
.
.
.
<% end %>
</div>
</div>
Ajax Call for this Form
function contact_check(){
var product_price_val = $('.price_unit').val();
var product_title_val = $('.product_item_title').val();
var quote_title_val = $('#prquote_title').val();
var contact_present = $(".selectize-input .item").length;
if (contact_present > 0 && quote_title_val != "" && product_title_val != "" && product_price_val != "") {
setTimeout(autoSavePost, 30000);
}
}
$(document).bind('keyup mouseup change mouseover click', function() {
contact_check();
});
function autoSavePost() {
$.ajax({
type: "POST",
url: '/quotes',
data: $("#new_quote").serialize(),
dataType: "script",
success: function(data) {
console.log(data)
// id = data;
// $('#quote_response').val(id);
}
});
setTimeout(autoSavePost, 30000);
}
Controller Action
def create
@quote = current_user.quotes.build(quote_params)
respond_to do |format|
if @quote.save!
format.html{
redirect_to @quote, notice: 'Quote was successfully created.'
}
format.js
else
render 'new'
end
end
end
Create.js.erb
$("#dynamic_form").html("<%= j render(:partial => 'edit_form', :locals => {quote: @quote}) %>");
window.history.pushState('edit', 'Quote', '/quotes/<%= @quote.slug %>/edit ');
This File Render the edit_form which as the same as new but on the script is different for Ajax call, but I comment is for now so actually see, what's going on. I didn't understand why my new form script keeps running and give me the error of
ActionController::ParameterMissing (param is missing or the value is empty: quote):
Some Logs to Actually see what is happening with this code
Started POST "/quotes" for 127.0.0.1 at 2019-05-21 22:27:22 +0500
Processing by QuotesController#create as JS
Parameters: {"utf8"=>"✓", "authenticity_token"=>"gpJNa8DNlSvox4LOCY4itfhnTqD3Za7TKrQ9zYsDP6rzwN9+wqaxwbxzKLFQvRA3JUdRuaEw9xcrZe/jJYea9A==", "quote"=>{"valid_until"=>"2019-06-20", "created_on"=>"2019-05-21", "discount"=>"", "currency"=>"£", "currency_symbol"=>"£", "tax_rule"=>"VAT Exclusive (Inclusive Total)", "contact_id"=>"1", "title"=>"Hahahhahah Zabardast bhai zabadast", "products_attributes"=>{"0"=>{"is_optional"=>"false", "is_optional_checked"=>"false", "is_multiple"=>"false", "is_multiple_checked"=>"false", "_destroy"=>"false", "item_code"=>"010", "heading"=>"Product", "description"=>"Description", "position"=>"1", "unit_price"=>"1203030", "quantity"=>"1", "is_editable"=>"", "item_total"=>"1203030.00", "category"=>"1", "tax_rule_id"=>"1", "discount"=>"", "cost_price"=>"", "has_subscription"=>"", "subscription_unit"=>"", "subscription_plan"=>"Week", "subscription_number"=>""}}, "total_quote_price"=>"1443636.00", "text_items_attributes"=>{"0"=>{"_destroy"=>"false", "heading"=>"", "description"=>"", "position"=>"1"}}}}
User Load (0.7ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2 [["id", 1], ["LIMIT", 1]]
(0.3ms) BEGIN
Quote Exists (0.5ms) SELECT 1 AS one FROM "quotes" WHERE "quotes"."id" IS NOT NULL AND "quotes"."slug" = $1 LIMIT $2 [["slug", "dbfnhkoeagtycsljrxivmwuqzp"], ["LIMIT", 1]]
TaxRule Load (0.5ms) SELECT "tax_rules".* FROM "tax_rules" WHERE "tax_rules"."id" = $1 LIMIT $2 [["id", 1], ["LIMIT", 1]]
Quote Create (0.8ms) INSERT INTO "quotes" ("title", "slug", "currency", "tax_rule", "currency_symbol", "total_quote_price", "created_on", "valid_until", "created_at", "updated_at", "contact_id", "user_id") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12) RETURNING "id" [["title", "Hahahhahah Zabardast bhai zabadast"], ["slug", "dbfnhkoeagtycsljrxivmwuqzp"], ["currency", "£"], ["tax_rule", "VAT Exclusive (Inclusive Total)"], ["currency_symbol", "£"], ["total_quote_price", 1443636.0], ["created_on", "2019-05-21"], ["valid_until", "2019-06-20"], ["created_at", "2019-05-21 22:27:22.370808"], ["updated_at", "2019-05-21 22:27:22.370808"], ["contact_id", 1], ["user_id", 1]]
Product Create (0.5ms) INSERT INTO "products" ("item_code", "heading", "category", "position", "description", "unit_price", "quantity", "item_total", "subscription_plan", "is_optional", "is_multiple", "quote_id", "tax_rule_id", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15) RETURNING "id" [["item_code", "010"], ["heading", "Product"], ["category", "1"], ["position", 1], ["description", "Description"], ["unit_price", 1203030.0], ["quantity", 1], ["item_total", 1203030.0], ["subscription_plan", 0], ["is_optional", false], ["is_multiple", false], ["quote_id", 140], ["tax_rule_id", 1], ["created_at", "2019-05-21 22:27:22.374411"], ["updated_at", "2019-05-21 22:27:22.374411"]]
(19.6ms) COMMIT
[ActiveJob] Enqueued QuoteJob (Job ID: 5beee9d7-88fc-4295-9134-02b74dbd25e5) to Sidekiq(default) at 2019-06-19 19:00:00 UTC with arguments: #<GlobalID:0x00007f8f7149be18 @uri=#<URI::GID gid://proposl/Quote/140>>
Rendering quotes/create.js.erb
Contact Load (0.7ms) SELECT "contacts".* FROM "contacts" WHERE "contacts"."user_id" = $1 [["user_id", 1]]
Contact Load (0.6ms) SELECT "contacts".* FROM "contacts" WHERE "contacts"."id" = $1 LIMIT $2 [["id", 1], ["LIMIT", 1]]
Product Load (0.5ms) SELECT "products".* FROM "products" WHERE "products"."quote_id" = $1 [["quote_id", 140]]
ImageAttachment Load (0.3ms) SELECT "image_attachments".* FROM "image_attachments" WHERE "image_attachments"."owner_id" = $1 AND "image_attachments"."owner_type" = $2 [["owner_id", 353], ["owner_type", "Product"]]
Category Load (0.4ms) SELECT "categories".* FROM "categories" WHERE "categories"."user_id" = $1 AND "categories"."active" = $2 ORDER BY "categories"."id" ASC LIMIT $3 [["user_id", 1], ["active", true], ["LIMIT", 1]]
Category Load (0.3ms) SELECT "categories".* FROM "categories" WHERE "categories"."user_id" = $1 [["user_id", 1]]
TaxRule Load (0.2ms) SELECT "tax_rules".* FROM "tax_rules" WHERE "tax_rules"."user_id" = $1 [["user_id", 1]]
TaxRule Load (0.4ms) SELECT "tax_rules".* FROM "tax_rules" WHERE "tax_rules"."user_id" = $1 AND "tax_rules"."active" = $2 ORDER BY "tax_rules"."id" ASC LIMIT $3 [["user_id", 1], ["active", true], ["LIMIT", 1]]
CACHE TaxRule Load (0.0ms) SELECT "tax_rules".* FROM "tax_rules" WHERE "tax_rules"."user_id" = $1 AND "tax_rules"."active" = $2 ORDER BY "tax_rules"."id" ASC LIMIT $3 [["user_id", 1], ["active", true], ["LIMIT", 1]]
TextItem Load (0.3ms) SELECT "text_items".* FROM "text_items" WHERE "text_items"."parent_id" = $1 AND "text_items"."parent_type" = $2 [["parent_id", 353], ["parent_type", "Product"]]
Rendered quotes/_text_item_fields.html.erb (1.0ms)
Rendered quotes/_product_fields.html.erb (18.8ms)
CACHE Category Load (0.0ms) SELECT "categories".* FROM "categories" WHERE "categories"."user_id" = $1 AND "categories"."active" = $2 ORDER BY "categories"."id" ASC LIMIT $3 [["user_id", 1], ["active", true], ["LIMIT", 1]]
CACHE TaxRule Load (0.0ms) SELECT "tax_rules".* FROM "tax_rules" WHERE "tax_rules"."user_id" = $1 AND "tax_rules"."active" = $2 ORDER BY "tax_rules"."id" ASC LIMIT $3 [["user_id", 1], ["active", true], ["LIMIT", 1]]
CACHE TaxRule Load (0.0ms) SELECT "tax_rules".* FROM "tax_rules" WHERE "tax_rules"."user_id" = $1 AND "tax_rules"."active" = $2 ORDER BY "tax_rules"."id" ASC LIMIT $3 [["user_id", 1], ["active", true], ["LIMIT", 1]]
Rendered quotes/_text_item_fields.html.erb (0.4ms)
Rendered quotes/_product_fields.html.erb (9.9ms)
TextItem Load (0.5ms) SELECT "text_items".* FROM "text_items" WHERE "text_items"."parent_id" = $1 AND "text_items"."parent_type" = $2 [["parent_id", 140], ["parent_type", "Quote"]]
Rendered quotes/_text_item_fields.html.erb (0.7ms)
Rendered quotes/_address_fields.html.erb (1.1ms)
Rendered quotes/_contact_detail_fields.html.erb (0.7ms)
Rendered quotes/_new_contact.html.erb (8.4ms)
Rendered quotes/_edit_form.html.erb (59.1ms)
Rendered quotes/create.js.erb (63.0ms)
Completed 200 OK in 121ms (Views: 64.2ms | ActiveRecord: 27.0ms)
Started POST "/quotes" for 127.0.0.1 at 2019-05-21 22:27:22 +0500
Processing by QuotesController#create as JS
User Load (1.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2 [["id", 1], ["LIMIT", 1]]
Completed 500 in 8ms (ActiveRecord: 1.3ms)
ActionController::ParameterMissing (param is missing or the value is empty: quote):
app/controllers/quotes_controller.rb:194:in `quote_params'
Started POST "/quotes" for 127.0.0.1 at 2019-05-21 22:27:23 +0500
Processing by QuotesController#create as JS
User Load (2.5ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2 [["id", 1], ["LIMIT", 1]]
Completed 500 in 21ms (ActiveRecord: 2.5ms)
ActionController::ParameterMissing (param is missing or the value is empty: quote):
app/controllers/quotes_controller.rb:194:in `quote_params'
Started POST "/quotes" for 127.0.0.1 at 2019-05-21 22:27:23 +0500
Processing by QuotesController#create as JS
User Load (0.6ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2 [["id", 1], ["LIMIT", 1]]
Completed 500 in 4ms (ActiveRecord: 0.6ms)
ActionController::ParameterMissing (param is missing or the value is empty: quote):
app/controllers/quotes_controller.rb:194:in `quote_params'
Started POST "/quotes" for 127.0.0.1 at 2019-05-21 22:27:24 +0500
Processing by QuotesController#create as JS
User Load (2.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2 [["id", 1], ["LIMIT", 1]]
Completed 500 in 15ms (ActiveRecord: 2.1ms)
ActionController::ParameterMissing (param is missing or the value is empty: quote):
app/controllers/quotes_controller.rb:194:in `quote_params'
Started POST "/quotes" for 127.0.0.1 at 2019-05-21 22:27:24 +0500
Processing by QuotesController#create as JS
User Load (1.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2 [["id", 1], ["LIMIT", 1]]
Completed 500 in 9ms (ActiveRecord: 1.1ms)
ActionController::ParameterMissing (param is missing or the value is empty: quote):
app/controllers/quotes_controller.rb:194:in `quote_params'
Started POST "/quotes" for 127.0.0.1 at 2019-05-21 22:27:24 +0500
Processing by QuotesController#create as JS
User Load (2.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2 [["id", 1], ["LIMIT", 1]]
Completed 500 in 13ms (ActiveRecord: 2.0ms)
ActionController::ParameterMissing (param is missing or the value is empty: quote):
app/controllers/quotes_controller.rb:194:in `quote_params'
Started POST "/quotes" for 127.0.0.1 at 2019-05-21 22:27:25 +0500
Processing by QuotesController#create as JS
User Load (1.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2 [["id", 1], ["LIMIT", 1]]
Completed 500 in 8ms (ActiveRecord: 1.2ms)
Started POST "/quotes" for 127.0.0.1 at 2019-05-21 22:27:25 +0500
ActionController::ParameterMissing (param is missing or the value is empty: quote):
app/controllers/quotes_controller.rb:194:in `quote_params'
Processing by QuotesController#create as JS
User Load (0.7ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2 [["id", 1], ["LIMIT", 1]]
Completed 500 in 4ms (ActiveRecord: 0.7ms)
ActionController::ParameterMissing (param is missing or the value is empty: quote):
app/controllers/quotes_controller.rb:194:in `quote_params'
Started POST "/quotes" for 127.0.0.1 at 2019-05-21 22:27:26 +0500
Processing by QuotesController#create as JS
User Load (1.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2 [["id", 1], ["LIMIT", 1]]
Completed 500 in 12ms (ActiveRecord: 1.0ms)
ActionController::ParameterMissing (param is missing or the value is empty: quote):
app/controllers/quotes_controller.rb:194:in `quote_params'
Started GET "/quotes/dbfnhkoeagtycsljrxivmwuqzp/edit" for 127.0.0.1 at 2019-05-21 22:27:32 +0500
Processing by QuotesController#edit as HTML
Parameters: {"id"=>"dbfnhkoeagtycsljrxivmwuqzp"}
User Load (2.8ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2 [["id", 1], ["LIMIT", 1]]
Quote Load (8.3ms) SELECT "quotes".* FROM "quotes" WHERE "quotes"."status" != $1 AND "quotes"."slug" = $2 LIMIT $3 [["status", 5], ["slug", "dbfnhkoeagtycsljrxivmwuqzp"], ["LIMIT", 1]]
Quote Load (1.6ms) SELECT "quotes".* FROM "quotes" WHERE "quotes"."slug" = $1 LIMIT $2 [["slug", "dbfnhkoeagtycsljrxivmwuqzp"], ["LIMIT", 1]]
Rendering quotes/edit.html.erb within layouts/application
Contact Load (0.6ms) SELECT "contacts".* FROM "contacts" WHERE "contacts"."user_id" = $1 [["user_id", 1]]
Contact Load (0.6ms) SELECT "contacts".* FROM "contacts" WHERE "contacts"."id" = $1 LIMIT $2 [["id", 1], ["LIMIT", 1]]
Product Load (0.9ms) SELECT "products".* FROM "products" WHERE "products"."quote_id" = $1 [["quote_id", 140]]
ImageAttachment Load (0.5ms) SELECT "image_attachments".* FROM "image_attachments" WHERE "image_attachments"."owner_id" = $1 AND "image_attachments"."owner_type" = $2 [["owner_id", 353], ["owner_type", "Product"]]
Category Load (0.8ms) SELECT "categories".* FROM "categories" WHERE "categories"."user_id" = $1 AND "categories"."active" = $2 ORDER BY "categories"."id" ASC LIMIT $3 [["user_id", 1], ["active", true], ["LIMIT", 1]]
Category Load (0.3ms) SELECT "categories".* FROM "categories" WHERE "categories"."user_id" = $1 [["user_id", 1]]
TaxRule Load (0.5ms) SELECT "tax_rules".* FROM "tax_rules" WHERE "tax_rules"."user_id" = $1 [["user_id", 1]]
TaxRule Load (0.6ms) SELECT "tax_rules".* FROM "tax_rules" WHERE "tax_rules"."user_id" = $1 AND "tax_rules"."active" = $2 ORDER BY "tax_rules"."id" ASC LIMIT $3 [["user_id", 1], ["active", true], ["LIMIT", 1]]
CACHE TaxRule Load (0.0ms) SELECT "tax_rules".* FROM "tax_rules" WHERE "tax_rules"."user_id" = $1 AND "tax_rules"."active" = $2 ORDER BY "tax_rules"."id" ASC LIMIT $3 [["user_id", 1], ["active", true], ["LIMIT", 1]]
TextItem Load (0.5ms) SELECT "text_items".* FROM "text_items" WHERE "text_items"."parent_id" = $1 AND "text_items"."parent_type" = $2 [["parent_id", 353], ["parent_type", "Product"]]
Rendered quotes/_text_item_fields.html.erb (1.8ms)
Rendered quotes/_product_fields.html.erb (45.9ms)
CACHE Category Load (0.0ms) SELECT "categories".* FROM "categories" WHERE "categories"."user_id" = $1 AND "categories"."active" = $2 ORDER BY "categories"."id" ASC LIMIT $3 [["user_id", 1], ["active", true], ["LIMIT", 1]]
CACHE TaxRule Load (0.2ms) SELECT "tax_rules".* FROM "tax_rules" WHERE "tax_rules"."user_id" = $1 AND "tax_rules"."active" = $2 ORDER BY "tax_rules"."id" ASC LIMIT $3 [["user_id", 1], ["active", true], ["LIMIT", 1]]
CACHE TaxRule Load (0.0ms) SELECT "tax_rules".* FROM "tax_rules" WHERE "tax_rules"."user_id" = $1 AND "tax_rules"."active" = $2 ORDER BY "tax_rules"."id" ASC LIMIT $3 [["user_id", 1], ["active", true], ["LIMIT", 1]]
Rendered quotes/_text_item_fields.html.erb (0.5ms)
Rendered quotes/_product_fields.html.erb (17.8ms)
TextItem Load (0.5ms) SELECT "text_items".* FROM "text_items" WHERE "text_items"."parent_id" = $1 AND "text_items"."parent_type" = $2 [["parent_id", 140], ["parent_type", "Quote"]]
Rendered quotes/_text_item_fields.html.erb (0.5ms)
Rendered quotes/_address_fields.html.erb (1.7ms)
Rendered quotes/_contact_detail_fields.html.erb (0.9ms)
Rendered quotes/_new_contact.html.erb (10.4ms)
Rendered quotes/_edit_form.html.erb (110.3ms)
Rendered quotes/edit.html.erb within layouts/application (112.2ms)
StripeCustomer Load (0.6ms) SELECT "stripe_customers".* FROM "stripe_customers" WHERE "stripe_customers"."user_id" = $1 LIMIT $2 [["user_id", 1], ["LIMIT", 1]]
Rendered layouts/_header_login.html.erb (1.1ms)
Completed 200 OK in 314ms (Views: 220.7ms | ActiveRecord: 48.7ms)
This Keeps running in the Logs like forever even I rendered the edit_form page and the new script gone but it keeps hitting with the same ajax call to the create action.
I am also providing the Edit form script so I explain what I want to do
function contact_check(){
var product_price_val = $('.price_unit').val();
var product_title_val = $('.product_item_title').val();
var quote_title_val = $('#prquote_title').val();
var contact_present = $(".selectize-input .item").length;
if (contact_present > 0 && quote_title_val != "" && product_title_val != "" && product_price_val != "") {
setTimeout(autoSavePost, 60000);
}
}
$(document).bind('keyup mouseup change mouseover click', function() {
contact_check();
});
function autoSavePost() {
$.ajax({
type: "PUT",
url: "quotes/<%#= quote.id %>",
data: $("#edit_quote").serialize(),
dataType: "script",
success: function(data) {
console.log(data)
// id = data;
// $('#quote_response').val(id);
}
});
setTimeout(autoSavePost, 60000);
}
The above code is commented out for now but this what I want to do afterwards.
Any Solution or more better Approach Thanks in Advance.
回答1:
After a lot of Effort and some help from my mate who actually knows how J Query works! He just explained that my script is doing the wrong work. We have to manipulate it.
So we Researched on it and comes up on a decision that when the New Page is open for the Quote, we have to just send the request one time and then render the whole page with the Edit form and then in the Edit Page we write the Actual Script for Auto Save Feature
So, I am Explaining the new Form Script
function contact_check(){
var product_price_val = $('.price_unit').val();
var product_title_val = $('.product_item_title').val();
var quote_title_val = $('#prquote_title').val();
var contact_present = $(".selectize-input .item").length;
if (contact_present > 0 && quote_title_val != "" && product_title_val != "" && product_price_val != "") {
autoSavePost();
}
}
var contact_present = $(".selectize-input .item").length;
if(contact_present > 0){
$('.price_unit, .product_item_title, #prquote_title').on('blur',function(){
contact_check();
});
}
else{
$(document).on('change',function(){
contact_check();
});
}
function autoSavePost() {
$.ajax({
type: "POST",
url: '/quotes',
data: $("#new_quote").serialize(),
dataType: "script",
});
}
What this script is doing is that Checking some Validations on some Fields and then Send the Post Request to the Controller which just render the edit form after inserting the Object in DB, or better say after persisting the Record.
After Words the Edit Page is Rendered we wrote a Script there to just update the object after some Interval
function contact_check(){
setTimeout(autoSavePost, 60000);
}
$(document).on('change',function(){
contact_check();
});
function autoSavePost() {
var product_price_val = $('.price_unit').val();
var product_title_val = $('.product_item_title').val();
var quote_title_val = $('#prquote_title').val();
var contact_present = $(".selectize-input .item").length;
if (contact_present > 0 && quote_title_val != "" && product_title_val != "" && product_price_val != "") {
$.ajax({
type: "PATCH",
url: "/quotes/<%= quote.slug %>",
data: $("#edit_quote").serialize(),
dataType: "script",
success: function(data) {
console.log("data")
}
});
setTimeout(autoSavePost, 60000);
}
}
So, this approach is quite helpful and its a fully Working Auto Save Form Feature and it can be implemented on any type of Object. Thanks !
Any more optimized techniques and better solutions are always welcome !
来源:https://stackoverflow.com/questions/56244349/dynamically-auto-save-rails-form-using-ajax-is-failing-at-some-point