Just being very basic here. I'm trying to post an activeResource as Json and recover it on the other side. At present, I seem to be able to send JSON but not recreate it into an Object of my choice.
I've tried my hand at generating a post request with Json in Ruby.
There are 2 parts to be aware of, The active resource on client side and the controller handling the incoming request. The errors usually come down to 406 (request not acceptable) or 422 (Unprocessable Entity)
I suppose the basic question is how can I fix these?
Here is my active resource class.
class UserRequest < ActiveResource::Base
self.site = "http://localhost:3008"
self.format = :json
#do not define defs as 'self'.whatever
def post_me
res = Net::HTTP.post_form(URI.parse('http://127.0.0.1:3008/user_requests.xml'),
{'url' =>'www.stackoverflow.com', 'depth' => '50'})
end
end
#Just to clarify. If im sending Json, I change the URI to .json and If I'm using xml, I #remove the self.format because active resource is XML by default
and here is line in controller which turns it to active record. controllers titled UserRequestsController
def add_request
#user_request = UserRequest.new(params[:user_request])
.
.
. end
route is
match '/user_requests(.:format)' => 'user_requests#add_request', :via =>:post
Now a few things before everyone face palms and goes mad at me.
I'm aware that in the def for add_request I'm missing JSON.parse. This is because when I include it I get 500 and an uninitialized constant error on server side. The gem is definitely installed and I'm not the only one whos had the problem but sadly no fixes.
http://railsforum.com/viewtopic.php?id=4654
http://railsforum.com/viewtopic.php?id=28301
So theres one question is how do i fix the parse so that it works the way I want to as I'm assuming the 406 is because its receiving Json but not sending it.
This would be ideal however if its not possible or someone can think of a reason why I should use XML, then perhaps they could take a look at this and tell me why I might be getting it on server side
Started POST "/user_requests.xml" for 127.0.0.1 at Thu Jul 14 09:38:34 +0100 2011
Processing by UserRequestsController#add_request as XML
Parameters: {"depth"=>"50", "url"=>"www.stackoverflow.com"}
SQL (0.2ms) SELECT 1 FROM "user_requests" WHERE ("user_requests"."url" IS NULL) LIMIT 1
Completed 422 Unprocessable Entity in 18ms (Views: 3.9ms | ActiveRecord: 0.2ms)
Just one last thing is the reasoin I'm not using .save is because the lead on my intern program doesn't like and says its not fit for purpose.
I had a similar problem. Try modifying your "add_request" method like this:
def add_request
#user_request = UserRequest.new(params[:user_request])
format.json { render :json => #user_request, :status => :created, :location => #user_request }
end
Related
I've read several | articles about using params.require(...) in Rails, but nothing that shows them in a non-trivial, real-world scenario.
Specifically, the following URL will be called:
GET http://myapp.example.com/widgets/{clientUuid}
Where {clientUuid} will be a string. I just want to check (from the proper controller action) whether the provided {clientUuid} is non-null and non-empty. I'm wondering if I can just do this:
if params.require(params[:clientUuid]) == null
response = { "error" => "bad client uuid" }
render json: response, status: :bad_request
return
end
And have non-nullness/non-emptiness enforced? If not, what can I do to achieve my desired result?
You're overcomplicating a simple GET request by messing up the route and using a method thats meant for a completely different use.
The idea is that .requires should be used for non-idempotent request methods (POST, PUT,PATCH) where the request contains a body with parameters. It lets you take a single key from the params and whitelist the params contained - which matches the Rails ideom of nesting inputs in a hash with the name of the resource as the root key.
In that case using .requires lets you return a response code to the client that indicates that the request cannot be processed (422 - Unprocessable Entity) as the request body does not have the right structure.
While you could potentially use it creatively on a GET request its wrong from a restful application engineering standpoint. In your case you should be returning a 404 - Not found response code if the clientUuid does not match a record. Usually in rails this is done by using .find which will raise a ActiveRecord::RecordNotFound exception which the framework catches.
Additionally if you have declared the route properly in the first place rails would actually give a 404 automatically as the request would not match if the id segment is missing.
class WidgetsController < ApplicationController
def show
#widget = Widget.find(params[:clientUuid])
end
end
If you want you could bail early so that the database is never queried if the param does not match a condition:
class WidgetsController < ApplicationController
def show
raise ActiveRecord::RecordNotFound if params[:clientUuid].blank?
#widget = Widget.find(params[:clientUuid])
end
end
You can just write:
if params[:clientUuid].blank?
response = { "error" => "bad client uuid" }
render json: response, status: :bad_request
return
end
With params.require it is a bit more difficult, because require raises a ActionController::ParameterMissing exception if the parameter is missing, but allows the parameter to return false (what I guess is still invalid in your example):
begin
uuid = params.require(:cliendUuid)
rescue ActionController::ParameterMissing
# nothing to do, just ensure the exceptions is rescued
end
unless uuid
# handle missing uuid
end
Or:
begin
uuid = params.require(:cliendUuid) || raise ActionController::ParameterMissing
rescue ActionController::ParameterMissing
# handle missing uuid
end
The article you posted re strong parameters is specifically about protecting your database data from user input, usually provided by forms.
params.require(:user).permit(:username)
The above code specifies that for the model User only allow the attribute username to be touched. If you try to update or create a user record in the user table with any other attribute e.g. email, you would get an error because the email attribute has not been 'permitted'. This is what is meant by whitelisting. You will only see the above code in create or update controller methods, or any other method that amends the data in some way. (An exception, of course, is deleting a record).
In your example, the parameter is provided as part of the url which you can also access via the rails provided params hash. However, as your method is not interacting with the db, you don't need to run it through the permit method.
This resource may help.
I am trying to test receive JSON webhooks from Stripe.
I have read:
Stripe Webhook on Rails
https://stripe.com/docs/webhooks
They require a 200 status response in order to acknowledge receipt.
I want to solve this before moving on to dealing with the JSON.
routes
post 'webhook' => 'web_hook#webhook'
controller
Stripe.api_key = "sk_test_whatsupbuttercup"
class WebHookController < ApplicationController
protect_from_forgery :except => :webhook
def webhook
render status: 200
end
end
With this setup, when I test a webhook, Stripe receives a 500 error.
If you only want to return a status use
head :ok
Instead of render. :ok is the corresponding symbol for 200 but you can also use it with the status code itself.
head 200
A full list of codes and corresponding symbols can be found here...
http://guides.rubyonrails.org/layouts_and_rendering.html
Whenever you get a 500 error (or any time you're confused about how your app is behaving actually) you should look in your logs. In this case you'll probably find that there's an ActionView::MissingTemplate error because you're rendering but not including anything to render.
When Rails responds to an HTTP request, it's HTTP response will always be correctly headed up with an appropriate HTTP response code. This can be for successful operations (a 2xx code), such as the creation of a new ActiveRecord in the database, or for errors (a 4xx). In the latter case a rendered HTML page is supplied containing information about the error (a backtrace, etc).
My app requires that all Rails HTTP responses take the form of JSON, so I am writing my own code to render these HTTP responses accordingly. A number of tutorials talk about writing something like this to render such responses (in this example, located in user_account_controller.rb where UserAccount is the name of an ActiveRecord model):
# method to create a UserAccount object based on supplied user_account_params
def create
#user_account = UserAccount.create!(user_account_params)
if #user_account
render :status => 201, :json => {
'message' : 'Operation was successful!"
}
end
end
And, if an exception is thrown, it is possible to bind a customer exception handler as follows:
# In ApplicationController
rescue_from Exception, :with => :json_exception_handler
def json_exception_handler(exception)
render :status => 422, :json => {
:exception => {
:backtrace => exception.backtrace,
:message => exception.message
}
}
end
The problem with both of these solutions is that they require me to statically set the HTTP response codes to have the same value every time (201 and 422 in these examples). Rails already does a great job of automatically picking the best response code to use, depending on the type of error or type of successful operation. I don't want to have to reinvent the wheel badly by inventing my own response code structure for each error and operation in my app.
So my question is this: how do I supply the response code that Rails will have automatically chosen anyway, whilst retaining the ability to print out custom JSON?
I set my app to receive incoming emails via a post from a service. The controller that receives the posts looks a little like this:
class IncomingMailsController < ApplicationController
require 'mail'
skip_before_filter :verify_authenticity_token
def create
message = Mail.new(params[:message])
message_plain = (params[:plain])
Rails.logger.info 'message2.plain:'
Rails.logger.info message2
render :text => 'success', :status => 200 # a status of 404 would reject the mail
end
end
That successfully is delivering the entire email message, replies,forward history etc. The issue is I'd like to be able to extract just the actual reply text.
Currently I get:
That's not a bad idea. Lets try that out.
On Nov 17, 2010, at 4:18 PM, XXXXX # XXXXXXXX wrote:
> There's a new reply:
And I'd like to know how rails devs get just the reply:
That's not a bad idea. Lets try that out.
Ideas? Thanks
There's no guaranteed way to get the entire message however it's common practice to make use of a separator and then use some code to parse out the response line.
If you take a look at the code in the open source project teambox for example you see the something really similar to the following:
def strip_responses(body)
# For GMail. Matches "On 19 August 2010 13:48, User <proj+conversation+22245#app.teambox.com<proj%2Bconversation%2B22245#app.teambox.com>> wrote:"
body.strip.
gsub(/\n[^\r\n]*\d{2,4}.*\+.*\d#app.teambox.com.*:.*\z/m, '').
split("---------separator---------").first.
split("<div class='email'").first.
strip
end
Not a perfect gem, but you could try this gem from Github: Email Reply Parser
Have a look at the extended_email_reply_parser, which also includes github's email_reply_parser.
Install
Add it to the Gemfile:
# Gemfile
gem 'extended_email_reply_parser'
Usage
Then, you can parse the email reply like this:
message_plain = ExtendedEmailReplyParser.parse message
Example
Applied to your code:
class IncomingMailsController < ApplicationController
skip_before_filter :verify_authenticity_token
def create
message = Mail.new(params[:message])
message_plain = ExtendedEmailReplyParser.parse(message)
render :text => 'success', :status => 200 # a status of 404 would reject the mail
end
end
email_reply_parser vs. extended_email_reply_parser
The email_reply_parser is used and developed by github. It's small and efficient, but can't handle some edge cases, where the sender's email client doesn't properly format the previous conversation as quote.
The extended_email_reply_parser is an extendible wrapper around github's parser. It's not as efficient as the original one. But, it's easier to extend if the typical emails you're parsing are not handled quite right out of the box.
Resources
email_reply_parser
extended_email_reply_parser
Examples for extending the parser
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?
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
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