Announcement

Collapse
No announcement yet.
X
  • Filter
  • Time
Clear All
new posts

    RESTful Ruby on Rails

    Hi there, I am just starting to play with SmartClient, and it's pretty awesome so far! I am integrating it with a Ruby on Rails RESTful backend, and ran into a slight issue. For Rails, the PUT/DELETE controller methods (update/destroy) expect the id to be passed in on the URL instead of a parameter on the query string. SmartClient right now doesn't seem to provide a way to dynamically alter the URL of a DataSource after it's created, so I went ahead and forked RestDataSource to do a little tweak that adds the id to the end of the URL when looking up the url for a PUT/DELETE:

    Code:
        getDataURL : function (dsRequest) { 
            var type = dsRequest.operationType;
    
            if (type == "fetch" && this.fetchDataURL != null) 
                return this.fetchDataURL;
            if (type == "update" && this.updateDataURL != null)
                return this.updateDataURL + "/" + dsRequest.data.id;
            if (type == "add" && this.addDataURL != null) 
                return this.addDataURL;
            if (type == "remove" && this.removeDataURL != null)
                return this.removeDataURL + "/" + dsRequest.data.id;
            return this.Super("getDataURL", arguments);
       },
    This works, but I'm sure it's not the best way to do it. Perhaps you guys can add a feature to the RestDataSource that allows the user to dynamically inject parameters into the path? For example, I might actually have a RESTful route that is "/libraries/3493/books/39483/author.xml", so I'd probably want to specify the URL to the data source as "/libraries/{library_id}/books/{book_id}/author.xml" so I can change the library_id at runtime to be the library that is bound via a foreign key on the DataSource.

    Hope this makes sense, thanks for all the effort put into the framework, it really shows!

    #2
    Hello Gfodor,

    Glad you're enjoying yourself :)

    The easier way to dynamically alter the target URL is to modify dsRequest.actionURL from DataSource.transformRequest(). Remember to call Super() to preserve the existing behavior of RestDataSource.

    Comment


      #3
      Fast reply! It seems that at the time transformRequest is called, actionURL is null on the dsRequest passed in. However, this implementation works:

      Code:
      isc.defineClass("RailsDataSource", "RestDataSource");
      
      isc.RailsDataSource.addProperties({
          operationBindings:[
             {operationType:"fetch", dataProtocol:"getParams"},
             {operationType:"add", dataProtocol:"postParams"},
             {operationType:"remove", dataProtocol:"postParams", requestProperties:{httpMethod:"DELETE"}},
             {operationType:"update", dataProtocol:"postParams", requestProperties:{httpMethod:"PUT"}}
          ],
      
          getDataURL : function (dsRequest) { 
              var url = this.Super("getDataURL", arguments);
      
              for (var key in dsRequest.data) {
                macro = "{" + key + "}";
      
                while (url.indexOf(macro) >= 0) {
                  url = url.replace(macro, escape(dsRequest.data[key]));
                }
              }
      
              return url;
          },
      });
      Is there any risk in the way I'm doing this? This makes it so you can specify the URL of the RestDataSource as "/{a}/{b}/{c}" and the parameters will be inserted.

      Comment


        #4
        It's technically an undocumented API. hence subject to change without backwards compatibility. transformRequest() is the better place to do it - actionURL is null in transformRequest because you haven't set fetchDataURL / addDataURL et al as shown in the docs for RestDataSource.

        Comment


          #5
          You can also take a look at this post.

          Comment


            #6
            Originally posted by Isomorphic
            It's technically an undocumented API. hence subject to change without backwards compatibility. transformRequest() is the better place to do it - actionURL is null in transformRequest because you haven't set fetchDataURL / addDataURL et al as shown in the docs for RestDataSource.
            No, those properties are definitely set, otherwise my code wouldn't be working. Inspecting the dsRequest when it gets passed into transformRequest via Firebug shows that it is lacking an actionURL property at the time that method is called. I'm positive those URLs are on the data source, any other ideas?

            david: Thanks, I'll check out your implementation as well!

            Comment


              #7
              Hi gfodor,

              You're right, the actionURL is actually null at that point, but if you were to populate it (potentially using the this.fetchDataUrURL, this.updateDataURL etc as a starting point) it will be respected.
              Last edited by Isomorphic; 25 Nov 2008, 12:17.

              Comment


                #8
                Thanks for your help. I haven't coded a generic method to solve this problem (RestDataSource with dynamic URI's) but I followed your advice and was able to fetch some records from a RESTful service.
                Code:
                @Override
                protected Object transformRequest(DSRequest dsRequest) {
                	if(dsRequest.getOperationType()==DSOperationType.FETCH){
                		if(dsRequest.getCriteria()!=null){
                			if(dsRequest.getCriteria().getValues().containsKey("groupId")){
                				dsRequest.setActionURL("rest/categories/group/"+dsRequest.getCriteria().getValues().get("groupId"));
                			}
                		}
                	}
                	return super.transformRequest(dsRequest);
                }
                This is way to simple, but shows how you should change the action url.

                Comment

                Working...
                X