Cloudmailin gets 500 from Heroku when delivering e-mails - ruby-on-rails-3

I'm using the Cloudmailin addon to receive e-mail from my Heroku app. However, Cloudmailin has not been able to deliver - or, rather, it gets 500 from Heroku every time (so the address is correct).
The error in Heroku logs is
Started POST "/incoming_mails" for 109.107.35.53 at 2013-02-27 08:54:22 +0000
2013-02-27T08:54:23+00:00 app[web.1]: Entering the controller! Controlling the e-mail!
2013-02-27T08:54:23+00:00 app[web.1]:
2013-02-27T08:54:23+00:00 app[web.1]: NoMethodError (undefined method `[]' for nil:NilClass):
2013-02-27T08:54:23+00:00 app[web.1]: app/controllers/incoming_mails_controller.rb:7:in `create'
My routing is correct; the "Entering the controller! Controlling the e-mail!" comes from the puts at the beginning of the class, so the class definitely gets entered.
# routes.rb
post '/incoming_mails' => 'incoming_mails#create'
The file itself looks like this:
# /app/controllers/incoming_mails_controller.rb
class IncomingMailsController < ApplicationController
skip_before_filter :verify_authenticity_token
def create
puts "Entering the controller! Controlling the e-mail!"
Rails.logger.info params[:headers][:subject]
Rails.logger.info params[:plain]
Rails.logger.info params[:html]
if User.all.map(&:email).include? params[:envelope][:from] # check if user is registered
#thought = Thought.new
#thought.body = params[:plain].split("\n").first
#thought.user = User.where(:email => params[:envelope][:from])
#thought.date = DateTime.now
if #thought.save
render :text => 'Success', :status => 200
else
render :text => 'Internal failure', :status => 501
end
else
render :text => 'Unknown user', :status => 404 # 404 would reject the mail
end
end
end
User and Thought are database resources used elsewhere without a problem. The saving procedure is the same that works in scaffolding-generated Thought controller. The params and Rails.logger logic I copied from a Cloudmailin Rails 3 example.
I'm really confused - where am I going wrong? I'd really appreciate any pointers.

It turns out, this is why you shouldn't code while sleep-deprived. The problem was simple: there is no such thing as params[:envelope][:from], there is only params[:from]). My assumption that :from would be a sub-element of :envelope was probably formed by looking at the pattern in the second "Cloudmailin in Rails on Heroku" example, where a code used to log subject is Rails.logger.log params[:envelope][:subject].
I realized this was the error after reading the API documentation for 'original' Cloudmailin format. It was exceptionally silly of me not to have found / looked for this resource in the first place.
After fixing this, the code still didn't work, because User.where(:email => params[:from]) only returned a Relation object, while User object was expected. The error in Heroku logs was the following:
ActiveRecord::AssociationTypeMismatch (User(#29025160) expected,
got ActiveRecord::Relation(#12334440)):
Since there can only be one user with some e-mail, the fix User.where(:email => params[:from]).first has no side-effects and results in correct behavior.

Related

Rspec test :create method for a nested resource

I'm trying to set up specs to properly run with my nested resource.
This is the test code I'm trying to properly set up
it "redirects to the created unit" do
post :create, {:course_id => #course.id , :unit => valid_attributes}
response.should redirect_to(course_unit_path(#course, Unit.last))
end
That essentially should try to create a nested resource "unit" for "course".
Unfortunatly I'm getting the following error on all POST DELETE and PUT tests
Failure/Error: post :create, {:course_id => #course.id , :unit => valid_attributes}
NoMethodError:
undefined method `unit_url' for #<UnitsController:0x000000059f1000>
That makes sense since unit_url should be course_unit_url but it's RSpec calling it...
How can I make RSpec select the right named path?
For all GET tests I passed the :course_id by hand.
This is what I did:
it "redirects to the created unit" do
unit_id = "barry"
Unit.any_instance.should_receive(:save).and_return(true)
Unit.any_instance.stub(:id).and_return(unit_id)
post :create, {:course_id => #course.to_param , :unit => valid_attributes}
response.should redirect_to(course_unit_path(#course, unit_id))
end
I decided that the point of this test was not that it created a new model and redirected it, but simply that it redirects. I have another spec to ensure it creates a new model. Another benefit to this approach is that it doesn't touch the database so it should run a little faster.
I hope that helps.
Edit:
I also just noticed I have this in my before :each section which may be relevant:
Course.stub!(:find).and_return(#course)
Edit again:
In this case, there was code in the controller which was doing the offending call. As per comment below.

Correct routing for short url by username in Rails

I am trying to replace user profile views of the sort
/users/1
with
/username
I'm aware this means I'll need to check for collisions of various kinds. I've consulted the following similar SO questions:
Ruby on rails routing matching username
customize rails url with username
Routing in Rails making the Username an URL:
routing error with :username in url
Here are the various failed routes.rb route definitions I've tried, and associated errors:
match "/:username" => "users#show", via: "get"
Here's the error:
ActiveRecord::RecordNotFound in UsersController#show
Couldn't find User without an ID
app/controllers/users_controller.rb:7:in `show'
Here is my corresponding users_controller:
6 def show
7 #user = User.find(params[:id])
8 end
match "/:username" => 'users#show', :as => :profile
Same error as above.
match "/:username", :controller => "users/:id", :action => 'show'
Routing Error
uninitialized constant Users
Try running rake routes for more information on available routes.
match '/:username', :controller => 'users', :action => 'show'
Same error as 1.
match '/:username', to: 'users/:id', via: 'show'
Server does not start.
match "/:username" => redirect("/users/:id")
Error:
ActiveRecord::RecordNotFound in UsersController#show
Couldn't find User with id=:id
Any idea why my routing is not working the same way that everyone else who asks this question's is?
Update
Just to take this issue out of the comments and put it in the question more cleanly. After making the change by #Ryan Bigg below, I had a routing problem in my redirect to profile when a new one is created. Here's my create code:
def create
#user = User.new(params[:user])
if #user.save
session[:user_id] = #user.id
flash[:success] = "Thank you for signing up."
redirect_to ('/'+#user.username)
#redirect_to #user, notice: "Thank you for signing up!"
else
render "new"
end
end
And here is my user.rb
def to_param
self.username
#username
end
However, the commented out redirect, which I think should work with the to_param update, doesn't work, while the ugly hackish one above it does. Why is the to_param overwrite, which worked for other people, not working on my app? My #update and #edit methods are also not working, as their redirects go to "users/1/edit" instead of "username/edit" if overwriting to_param doesn't take care of this.
The first one is correct, but isn't working because you're still attempting to do something like this inside your controller:
User.find(params[:username])
When you should instead be doing this:
User.find_by_username!(params[:username])
The first one will attempt to find by the primary key of your table, where the second one will, correctly, query on the username field instead.
In addition to the update for to_params, the bottom of the routes file needs the following line:
resources :users, :path => '/'

calling specific url in Rspec in integration test

I'm trying to do the following in rspec (know that I shouldn't have hardcoded value) in an integration test:
get '/api/get-other-items?id=5109'
The closest I could find was: call a specific url with rspec but it selects only a single item. I have tried the following:
get :controller => 'api', :action => 'get-other-items', :id => '5109'
get 'api/get-other-items', :id => '5109'
These are giving me a bad argument(expected URI object or URI string)
If I run as
get get_other_items, :id => '5109' q
I get
undefined local variable or method `get_other_items' for #<RSpec::Core::ExampleGroup::Nested_1:0x007f938fd65590>
but the route does exist:
Mon Jan 23$ rake routes | grep get_other_items
get_other_items /api/get-other-items(.:format) {:controller=>"api", :action=>"get_other_items"}
How would I perform this simple get?
thx
update for answer 1 comment
here's the rspec code in question:
it "testing getting other items for menu item" do
get get_other_items_path(:id => '5109')
JSON.parse(response.body)
puts response.body
Mon Jan 23$ rspec requests/get_other_items_spec.rb
F
Failures:
1) GetOtherItems testing getting other items for menu item
Failure/Error: JSON.parse(response.body)
JSON::ParserError:
743: unexpected token at 'this is not found '
# ./requests/get_other_items_spec.rb:19:in `block (2 levels) in <top (required)>'
Finished in 13.57 seconds
1 example, 1 failure
Failed examples:
The call should be get get_other_items_path(:id => 5109) - you need to add path to the name of the route, or url if you want the full URL instead of a relative path.
Your route doesn't look like it's taking a :id as a parameter, if you want to send an :id I would expect to see the following:
get_other_items /api/get-other-items/:id(.:format) {:controller=>"api", :action=>"get_other_items"}
Given the structure of your generated route I assume that you are using match to define the route (There is no HTTP verb in your route). To fix it try:
match 'api/get-other-items/:id' => 'api#get_other_items'
If instead you are using restful routes then it looks like you have specified a collection route rather than a member route. A collection route doesn't take an :id and is designed to return many records of the type you have specified. To make it a member route use the following:
resources :api do
get 'get_other_items', :on => :member
end
Once you get this working you should be able to try the following in rspec in your ApiController spec:
get :get_other_items, :id => '5109'
If neither of these options work please post your routes entry so we can try something else.

No POST from facebook using real-time updates in Rails, Heroku and Koala

This question is an expanded version of Facebook Real-time updated does not call our servers, that seems to be dead. Also, Realtime updates internal server error on Heroku using Koala is not helpful because I'm subscribing from the heroku console as pjaspers suggested.
I have an app (ruby 1.9.2p290 and Rails 3.1.3) that connects to facebook to get data from the current user. Everything is working ok with the koala gem (v1.2.1), but I'm polling the fb servers every time the users logs in. I would like to use facebook real-time updates, and I have read the following:
Koala manual on fb realtime updates: https://github.com/arsduo/koala/wiki/Realtime-Updates
Facebook page on realtime: https://developers.facebook.com/docs/reference/api/realtime/
I have set up the system in test mode and deployed to heroku successfully. I can subscribe to the user object and I get the GET request to my server, but no POST with updated information is ever received from facebook. If I issue a POST to my server manually everything works.
More information:
routes.rb
get '/realtime' => 'realtime#verify'
post '/realtime' => 'realtime#change'
generating
realtime GET /realtime(.:format) {:controller=>"realtime", :action=>"verify"}
POST /realtime(.:format) {:controller=>"realtime", :action=>"change"}
The controller (mock version, only to test if it's working):
class RealtimeController < ApplicationController
def verify
render :text => params["hub.challenge"]
end
def change
puts params.inspect
render :nothing => true
end
end
The subscription from the heroku console:
irb(main):004:0> #updates = Koala::Facebook::RealtimeUpdates.new(:app_id => ENV['FACEBOOK_APP_ID'], :secret => ENV['FACEBOOK_APP_SECRET'])
=> #<Koala::Facebook::RealtimeUpdates:0x00000004f5bca8 #app_id="XXXXXXX", #app_access_token="XXXXXXX", #secret="XXXXXXX", #graph_api=#<Koala::Facebook::API:0x00000004a8d7a8 #access_token="XXXXXXX">>
irb(main):005:0> #updates.list_subscriptions
=> [{"object"=>"user", "callback_url"=>"http://blah-blah-0000.herokuapp.com/realtime", "fields"=>["education", "email", "friends", "name", "website", "work"], "active"=>true}]
I don't know what to do next...
Maybe I am not triggering the correct changing events?
How do I see the list of users of my app? (right now it's a test app and the only user would be me)
Anyone with this kind of issue?
Is something wrong in the code?
Is facebook down? Is it the end of Internet?
Thank you for the help :)
You need to respond to the GET request with a challenge response. I have the same route for both POST and GET requests and use the following code:
route:
match "facebook/subscription", :controller => :facebook, :action => :subscription, :as => 'facebook_subscription', :via => [:get,:post]
controller:
def realtime_request?(request)
((request.method == "GET" && params['hub.mode'].present?) ||
(request.method == "POST" && request.headers['X-Hub-Signature'].present?))
end
def subscription
if(realtime_request?(request))
case request.method
when "GET"
challenge = Koala::Facebook::RealtimeUpdates.meet_challenge(params,'SOME_TOKEN_HERE')
if(challenge)
render :text => challenge
else
render :text => 'Failed to authorize facebook challenge request'
end
when "POST"
case params['object']
# Do logic here...
render :text => 'Thanks for the update.'
end
end
end
That should get you going with things... Note that to make a subscription I am using this:
#access_token ||= Koala::Facebook::OAuth.new(FACEBOOK_API_KEY,FACEBOOK_API_SECRET).get_app_access_token
#realtime = Koala::Facebook::RealtimeUpdates.new(:app_id => FACEBOOK_API_KEY, :app_access_token => #access_token)
#realtime.subscribe('user', 'first_name,uid,etc...', facebook_subscription_url,'SOME_TOKEN_HERE')
I think the key is that you properly respond to the GET request from Facebook. They use this to verify that they are contacting the correct server prior to sending confidential info about their users.
Also -- its been a while since I've looked at this, but if I remember correctly, I seem to recall having issues with anything besides default protocol port specifications within the callback URL. Ex: http://www.something.com:8080/subscription did not work -- it had to be http://www.something.com/subscription
Not sure if this might be the case with you, but make sure that you have permissions to access the object -user, permissions, page- properties (location, email, etc.)
In my case, I was trying to get notifications for changes on the location property without my app requiring the user_location permission. For the user object, look at the Fields section in this page https://developers.facebook.com/docs/reference/api/user/
Does Facebook know where your application is? Does it have a URL that it can resolve?

Troubleshooting empty params[] hash since Rails3 Upgrade

I have a named route that tests properly in the console and shows the :url_title which should be included in params[], yet params[] is always empty.
The question is, why is params[] empty? My expectation is it should have params[:url_title].
I also removed this route and used the default resource and params[] is still empty.
I've been checking params by using logger.
My app is an upgrade from Rails 2.3.5 to Rails 3.0.3.
Here's a code summary of what's going on.
# this is my route
match 'papers/:url_title' => 'papers#show', :as => :permalinkpaper
# this is link_to and the generated url being called
<%= link_to paper.title, paper_path(paper.url_title) %>
http://localhost:3000/papers/great-passion
# which properly matches to this controller#action for papers#show
def show
#paper = Paper.where(:url_title => params[:url_title]).first()
PaperHistory.add( current_user, #paper.id )
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #paper }
format.json { render :json => #paper }
format.mobile # { render :layout => false }
end
end
# which generals this error because the Paper looking returns noting because the params[:url_title] is nil
Called id for nil, which would mistakenly be 4 -- if you really wanted the id of nil, use object_id
# the log stack trace
Started GET "/papers/great-passion" for 127.0.0.1 at Mon Jan 24 23:04:04 -0600 2011
Processing by PapersController#show as HTML
SQL (0.7ms) SHOW TABLES
SQL (0.5ms) SHOW TABLES
Paper Load (0.7ms) SELECT `papers`.* FROM `papers` WHERE (`papers`.`url_title` IS NULL) ORDER BY title LIMIT 1
Completed in 119ms
RuntimeError (Called id for nil, which would mistakenly be 4 -- if you really wanted the id of nil, use object_id):
app/controllers/papers_controller.rb:43:in `show'
# I've validated the route in the console and it seems to know :url_title is the proper value
>> r = ActionController::Routing::Routes
>> r.recognize_path "/papers/great-passion"
=> {:action=>"show", :url_title=>"great-passion", :controller=>"papers"}
UPDATE: I have found that params[] are NOT empty when values are in the URL, such as when performing a search.
http://localhost:3000/papers?utf8=%E2%9C%93&keywords=passion
This successfully produces
Started GET "/papers?utf8=%E2%9C%93&keywords=passion" for 127.0.0.1 at Tue Jan 25 00:20:07 -0600 2011
Processing by PapersController#index as HTML
Parameters: {"utf8"=>"✓", "keywords"=>"passion"}
params: utf8✓keywordspassion
Thanks to all for the help. I was able to disassemble my app piece by piece and finally get params[] to show up.
The culprit was the open_id_authentication plugin.
I had some plugins in the vendors directory, so I removed them all and after hurdling a few resulting errors (b/c the plugins were now missing) everything worked. I systematically replaced plugins, and when I got to open_id_authentication found that the params[] again disappeared.
I had a different solution for this problem that I'll post here just in case somebody runs into the same issue. I was working on a password reset part of the site and tried various things such as putting the URL in manually, specifying the controller and action, using a bare (minimal) form and such, but all of it failed. The error given was the e-mail parameter was blank.
A look into the Exceptional logs showed that not just the e-mail parameter was blank, but even the UTF-8 check mark was missing. The only things in the params hash were the controller and action. Reloading the page also didn't turn up the usual spiel about re-submitting information.
It turns out the problem was in SSL. The page was trying to use SSL but didn't have permission and it was somehow silently killing the form. Hope that helps somebody.