I was putting together a quick inline editing feature in my first Rails app and just as I was getting it working it occurred to me that I may be violating RESTful principles. The edit updated an image name. To do so, it submits, via PUT to Image#update and passes the new modified name as image[name].
The database gets updated properly, but I need that value back so that my markup can reflect the name change. To do that, I was calling /images/:id.json, but that got me wondering whether a PUT request can "validly" (in that RESTful sort of way) return a value like this.
Thoughts?
Update: For whatever it's worth, I'm using jQuery and the jEditable plugin to do the inline editing. Here's my jEditable code:
$(document).ready( function() {
$('h2').editable(
'/images/' + $('#image-id').val() + '.json',
{
method: 'PUT',
name: 'image[name]',
submitdata: { authenticity_token: $('#auth-token').val() },
submit: 'Save',
cancel: 'Cancel'
}
);
})
And my Image#update method as it exists right now:
def update
#image = Image.find( params[:id] )
if #image.update_attributes( params[:image] )
flash[:notice] = "Successfully updated image."
respond_to do |format|
format.html { redirect_to #image }
format.json { render :json => #image.to_json }
end
else
render :action => 'edit'
end
end
If your concern is just that your update method with JSON provide a response body and not just a 200 OK (Rails's head :ok) then I don't think you need to be worried. The default response is 200 OK so the only difference between what you're doing and what Rails does by default (in its scaffolds) is that you're also including a response body. As far as I can tell proper REST etiquette only requires that you return a 200 OK and doesn't care about the response body, which is in line with what you're doing.
Beyond that all your code looks excellent.
Related
I have a controller action method that gets all records of establishments from the DB, I then want to share this response with a external entity which is a RhoMobile application, i used respond_to to format the response to JSON.
def index
#establishments = Establishment.index(params).includes(:assessor)
#json_establishments = Establishment.all
respond_to do |format|
format.html { redirect_to(establishments_url) }
format.json { render json: #json_establishments.as_json }
end
end
When i navigate to this action i get an error
net::ERR_TOO_MANY_REDIRECTS
in chrome developer tools on the console tab.
When i remove the { redirect_to(establishments_url) } next to the format.html it's working with a status of 406 (Not Acceptable) but if i would use the search in the action view that i created and click the browsers back button, i get something like:
ActionController::UnknownFormat in EstablishmentsController#index
ActionController::UnknownFormat
<div class="source hidden" id="frame-source-0">
<div class="info">
Extracted source (around line <strong>#219</strong>):
</div>
instead and when i refresh the page i get the expected view.
No wonder that it is stuck in redirect loop.
Reason:
establishments_url points to EstablishmentsController#index, and your default format must have been html. So, after setting the variables, it redirects to establishments_url, which again tries to load EstablishmentsController#index.
Solution:
Instead of redirecting to the URL, you need to consider rendering a view (as you did in JSON format).
format.html { render 'establishments/index' }
Ok. So I have a small XHR request where json is returned. On success the json is passed like this.
var myArr = JSON.parse(xmlhttp.responseText);
myMainFunction(myArr);
function myMainFunction(arr) {
var vShipTypeID = arr[0].victim.shipTypeID;
}
I need to send vShipTypeID to rails. My goal is to be sending this value back to activerecord and the information returned will go within a js, or json file to the respond_to statement in the controller.
#shipName = InvType.find(vShipTypeID).name
Here's the main idea. The client sends out the ID of the ship to rails, and rails returns the ship's name.
I know how to make the Ajax request.
I don't know how to process the request on the server end. Meaning after rails receives the data, where do I find it, and how to I convert it to be usable so that I can make an activerecord statement out of the value I received from the client?
Anyone?
A simple solution could be defining an action on your ship controller and define a route to it for example define a route in your routes.rb
get "/ship/:id/getname" => "ship#getname"
in your js file
$.get( "/ship/"+vShipID+"/getname")
.done(function(data) {
alert( "Ship name: " + data.name );
})
.fail(function() {
alert( "error" );
});
in you ship_controller.rb
class ship_controller <ApplicationController
....... #other methods
def getname
#shipname = Ship.find(params[:id]).name
if request.xhr
render :json => {name: #shipname} and return
else
redirect_to ship_path(params[:id])
end
end
........ #some other methods
end
You need to handle json requests in your controller check this question for details
for a quick example in your controller create a new action getnamefromid and call that controller from your client.
respond_to do |format|
format.json { render :json => #shipName }
end
I have a page that lets one create records - if the validations aren't satisfied, it redirects to the same page and shows an error message. Here's that snip from the controller:
def create
#signature = Signature.new(signature_params)
if #signature.save
redirect_to "/thanks"
else
redirect_to :back, :notice => error_messages(#signature)
end
end
The trouble is, this is resulting in a full page refresh - so the error message isn't visible because the input form is placed under the fold of the page. I can place it at the top of the page, of course, but is there a way to show the message without reloading the page? Thanks.
OK, so here's what I've settled on:
1) I'm handling validation on the client side with HTML5 "required" attributes - they were created for this explicit purpose and no other gems or plugins are needed. They are supported in all major browsers. Details in this article.
2) I've moved the error messages to the top of the page to handle the case in which a user either is on an old or mobile browser or has JavaScript disabled. Error messages must work with a complete request-response cycle (even if this means re-loading the page) before they work with anything else - this is the unobtrusive JavaScript approach.
3) For the AJAX version, I'm going to be using remote: => true on the form element as explained in the Rails guides. I might be making this open source once I'm done with the callback part of it, and will post a link here.
Obviously, handling errors with flash is the most uniform & DRY way to show the user what's going on, but if you're willing to think outside the box, you'll be able to use Ajax to accomplish a similar job by just handling the errors yourself:
Code Example
#app/controllers/signatures_controller.rb
def create
#signature = Signature.new(signature_params)
if #signature.save
#success = "true"
end
respond_to do |format|
format.js { #errors = error_messages(#signature) }
format.html {
if #success.defined?
redirect_to "/thanks"
else
redirect_to :back, :notice => error_messages(#signature)
end
}
end
end
#app/views/signatures/create.js.erb
<% unless #success.defined? %>
alert(<%=j #errors.inspect() %>)
<% end %>
#app/assets/javascripts/signatures.js
$(document).on("submit", "#signature_form", function() {
$.ajax({
url: "/signatures"
type: "POST"
data: $(this).parent().serialize(); //serialize the form (not the button)
error: function() {
alert("Sorry, there was an error!");
}
});
});
You'd actually be better using JSON for this. If you like the idea, I can refactor it to include JSON for you!
I am working on application where a a user can create a blog post and the blog post periodically updates every so often. I found a jQuery autosave plugin for handling the autosave but I am still running into problems.
When I debug using firebug I only see the GET request so therefore the page does not get updated and I am not sure how to call POST after the GET request.
It does not update as I type or every 3 seconds but it updates when I click outside of a form field. Anyway to have it so it updates every 3 seconds or so?
My code is listed below
application.js
jQuery(function($) {
$("#main-form").autosave({
callbacks: {
trigger: ["change", function() {
var self = this;
$("[name=save]").click(function() {
self.save();
});
}],
save: {
method: "ajax",
options: {
success: function() {
alert("saved!");
}
}
}
}
});
});
post_controller.rb
def update
#post = Post.find(params[:id])
respond_to do |format|
if #post.update_attributes(params[:post])
format.html { redirect_to semester_post_path, notice: 'post was successfully updated.' }
format.json { head :ok }
else
format.html { render action: "edit" }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
I'm sure you've moved on, but just to close the gap on this post. OnChange takes place when a field loses focus, so what you're seeing seems to be functioning as designed and normal for that design.
Here's a link to question/answer using timeouts to autosave via AJAX.
Autosave Opinion:
I'm not sure you really want envoke autosave until the document has been formally submitted for several reasons but I'll post my favorite 2.
Some forms tend to have a lot of moving parts for the back end storage and that first commit should be intentional before stuffing a bunch of data into tables. (IMHO)
another rationale behind leaving them alone (not auto-saving) before the first "real" submit is because until they hit submit they might not really want you to have that information in your system.
How often have you started a form on the web and then decided you didn't want to fill out that information after all? ... it would frustrate me to get a flyer or email or call from a site I actually decided to bail out of registration for!
On my site I have a simple model called Feed.
I want to make a link/button that will pull the Feed record with id=5 (for example) using AJAX.
The record that has been pulled should be displayed in a partial.
How can I do that ?
Thanks,
Oded
If you use jQuery, you could do sth like this:
In your controller you must respond to ajax request using the respond_to :js. Then you could either render directyl javascript which will be executed on your site, or the way I suggest you, to render json and parse it on the client side.
class YourController < ApplicationController
def index
#model = YourModel.all
respond_to do |format|
format.html
format.json {
render :json => #model.to_json
}
end
end
On the client side, just bind a click handler and then fetch the data using the path to your controller:
$("#your_link_id").click(function() {
$.getJSON('/path_to_your_controller', function(data) {
console.log(data);
});
}
The code is not tested, but it should work in that way.
Note: the console.log works with firefox but not with safari, try using firebug for console output.
Kind of long for a SO answer, but this should get you going:
http://www.tutorialspoint.com/ruby-on-rails-2.1/rails-and-ajax.htm
That's where I got started with AJAX on RAILS