Kyle Bachan
Kyle Bachan

Reputation: 1107

Get ID of Rails object as soon as it's created using jQuery

I'm trying to create multiple objects called "baseRules" in jQuery by calling post requests to my Rails controllers. Nested inside of this creation of objects are a subset of rules, called "matchTypes", that belong to the main rules. I need to assign a foreign_id to this subset for it to work correctly though. Is there any way to get the ID of the main rules object as soon as it's created in jQuery?

Here is my Javascript code:

for (var i = 0; i < baseRules.length; i++) {
    $.post('/rule_types', {
        name: baseRules[i][0],
        matchFlag: baseRules[i][1]
    }, function () {
        if (baseRules[i][1]) {
            for (var k = 0; k < baseRules[i][2].length; k++) {
                $.post('/match_types', {
                    name: matchType[i][2][k],
                    rule_type_id: ? ? ? ?
                }, function () {

                });
            }

        }
    });
}

And here are my controller methods:

class RuleTypesController < ApplicationController

    def create
        @ruleType = RuleType.new
        @ruleType.name = params[:name]
        @ruleType.matchFlag = params[:matchFlag]
        respond_to do |format|
            if @ruleType.save
                format.html{redirect_to root_path}
                format.js{}
            else
                format.html{}
                format.js{}
            end
        end
    end
end

class MatchTypesController < ApplicationController
    def create
        @matchType = MatchType.new
        @matchType.name = params[:name]
        matchType.rule_types_id = params[:rule_type_id] 
        respond_to do |format|
            if @ruleType.save
                format.html{redirect_to root_path}
                format.js{}
            else
                format.html{}
                format.js{}
            end
        end
    end

end

Upvotes: 1

Views: 516

Answers (1)

Richard Peck
Richard Peck

Reputation: 76774

In respect to your question (the extra "frills" can be addressed after), in order to receive the id of a newly created object, you should be able to capture it with the ajax:success request.


Ajax

Your flow is slightly complicated (Ajax is asynchronous), meaning that if you want to use the data you receive, you may have to use an ajax callback (not as complicated as it sounds)

If you create a new record, Rails will ALWAYS fire back a response. Inside this response, you can access the id attribute of the newly created record, allowing you to access the new ID for your object:

for (var i = 0; i < baseRules.length; i++) {
    $.post('/rule_types', {
        name: baseRules[i][0],
        matchFlag: baseRules[i][2]
    }, function (data) {
        var returnedData = JSON.parse(data);
        if (baseRules[i][3]) {
            for (var k = 0; k < baseRules[i][2].length; k++) {
                $.post('/match_types', {
                    name: matchType[i][2][k],
                    rule_type_id: returnedData.id //Calls the original "ID" of the returned post
                }, function () {

                });
            }

        }
    }, dataType: "json");
}

This will give you the ability to determine JSON responses in your controller:

#app/controllers/rules_types_controller.rb
class RuleTypesController < ApplicationController
    respond_to :js, :json, :html

    def create
        @ruleType = RuleType.new
        @ruleType.name = params[:name]
        @ruleType.matchFlag = params[:matchFlag]
        @ruleType.save

        respond_with @ruleType
        end
    end
end

Response

Although I think you'll make progress with what I've posted, you'll want to look at how you're using the $.post function. Although it should work as you have it now, you need to appreciate that if you try and use ajax functionality synchronously, it will likely freeze your UI whilst the request completes

The way to solve this is to use an Ajax callback. We've done this before:

function fetch(link, data, response, type = "script") {
   $.post(link, data, response(data), dataType: type);
}

for (var i = 0; i < baseRules.length; i++) {
    fetch('/rule_types', {
        name: baseRules[i][0],
        matchFlag: baseRules[i][2]
    }, function (data) {
        var returnedData = JSON.parse(data);
        if (baseRules[i][3]) {
            for (var k = 0; k < baseRules[i][2].length; k++) {
                fetch('/match_types', {
                    name: matchType[i][2][k],
                    rule_type_id: returnedData.id //Calls the original "ID" of the returned post
                });
            }

        }
    }, "json");
}

This should make it so that your ajax calls are truly asynchronous - updating only when they have the data returned from the server. I can re-factor this if you'd prefer

Upvotes: 1

Related Questions