views:

595

answers:

2

I am making an activeresource call to a service, and I'd like some custom error messages as feedback. I have some validations that aren't normal model validations, so I can't just return @object.errors.

So, for instance, one of my validations is this. Two objects have a many to many relationship, but I want to restrict one object to only have a limited number (say 2) of relationships to other objects. Here's some code:

In the client:

response = Customer.find(customer_id).put(:add_user, :user_id => user_id)

This puts a request to add a user to the customer. Then in the service I want to check that this addition is valid.

def add_user    
 @user = User.find(params[:user_id])
 @customer = Customer.find(params[:id])
 if @customer.users.length > 2
  render :xml => "ERR_only_2_users_allowed", :status => :unprocessable_entity
 end
end

Here's my problem. In active resource, if the return status is an error, the client side completely fails. I could change the status to 200 and I get back the body err msg fine, but this seems to defeat the purpose of having error reponse codes.

I can put the whole request call from the client in a begin/rescue block

begin
    response = Customer.find(customer_id).put(:add_user, :user_id => user_id)
  rescue ActiveResource::ResourceInvalid => e
    #return error code
end

but when I catch the 422 (unprocessable_entity) response, I get nothing of the body back, so I don't get my custom error message. response = nil

Does anyone know how I can achieve these custom error message with the proper response codes?

A: 

I think that your problem might be the response isn't an xml document but just a plain string. Try changing your render statement to something like:

render :xml => { :error => "ERR_only_2_users_allowed" }, :status => :unprocessable_entity
Corey
A: 

This may or may not be your problem, but both of ours seem very close. I'm using a custom put method, but his should work for you too. What's going on is that the code that does this:

rescue ResourceInvalid => error
     errors.from_xml(error.response.body)
end

Is only working with the standard save method. If you want errors added when other methods are called it looks like you need to do it yourself.

I had to add it to vendor/rails/activeresource/lib/active_resource/custom_methods.rb

Here is what my diff from git looks like: old code:

def put(method_name, options = {}, body = '')
  connection.put(custom_method_element_url(method_name, options), body, self.class.headers)
end

new code:

def put(method_name, options = {}, body = '')
  begin
    connection.put(custom_method_element_url(method_name, options), body, self.class.headers)
  rescue ResourceInvalid => error
    errors.from_xml(error.response.body)
  end
  self 
end

So look at the stack trace when get the exception thrown for the 422 and see which method it's calling exactly. Then add something like what I have and you should be good to go.

Don't ask me why the activeresource folks thought validations should only work with their save method. the save method does a create or update, but calling 'put or post' is the exact same thing, IMO. If we want validations to work on save we want them to work on put and post...anyway give it a shot.

I'm not sure if i need the self at the end...i may not. I'm not totally done with this as I just figured out how to make it work. Erik