I have Mandrill set up to send SMTP email on Heroku. My app is a rails app. When a user signs up, it sends the email as expected. However, I have also set up an "invitation" action that lets users invite other users by email. This is not getting sent, though the logs suggest it is and no error is thrown. I have:
config.action_mailer.raise_delivery_errors = true
Here are the relevant logs:
2014-07-17T07:23:06.739778+00:00 app[web.1]: Started POST "/courses/collaborate" for 88.112.253.45 at 2014-07-17 07:23:06 +0000
2014-07-17T07:23:06.885997+00:00 app[web.1]:
2014-07-17T07:23:06.886001+00:00 app[web.1]: Sent mail to *********#gmail.com (87ms)
2014-07-17T07:23:06.886794+00:00 app[web.1]: Redirected to http://**********.herokuapp.com/courses/*
2014-07-17T07:23:06.978772+00:00 app[web.1]: Started GET "/courses/*" for 88.112.253.45 at 2014-07-17 07:23:06 +0000
2014-07-17T07:23:06.742954+00:00 app[web.1]: Processing by CoursesController#collaborate as HTML
2014-07-17T07:23:06.742984+00:00 app[web.1]: Parameters: {"utf8"=>"✓", "authenticity_token"=>"*********", "user"=>"******", "email"=>"**********#gmail.com", "title"=>"************* Vocab", "course"=>"*", "key"=>"", "commit"=>"Send Invitation"}
2014-07-17T07:23:06.886962+00:00 app[web.1]: Completed 302 Found in 96ms (ActiveRecord: 0.0ms)
2014-07-17T07:23:06.981777+00:00 app[web.1]: Processing by CoursesController#show as HTML
2014-07-17T07:23:06.797782+00:00 app[web.1]: Rendered user_mailer/collaborate.text.erb (0.1ms)
It seems that the mail is getting sent before the user_mailer is rendered but I don't know why. I've done it like this:
1) A form sends the params you see above to the collaborate action in the controller.
2) This action looks like this:
def collaborate
#user = params[:user]
#title = params[:title]
#course = params[:course]
#email = params[:email]
#key = params[:key]
UserMailer.collaborate(#user, #title, #course, #email, #key).deliver
redirect_to course_path(#course), notice: 'Invitation sent!'
end
3) The UserMailer.collaborate looks like this:
def collaborate(user, title, course, email, key)
#user = user
#title = title
#course = course
#email = email
#key = key
mail from: #user, to: #email, subject: "Please join me creating a course!"
end
4) collaborate.text.erb is just a message that uses the instance variables I set up.
The solution is that the form was automatically generating a :put and not a :get request. For some reason this wasn't a problem on the local server but pushed to production it was preventing the mail getting sent out. The key is to override the default form_tag :put request with a :get request.
Related
Following the hartle tutorial here: https://www.learnenough.com/action-cable-tutorial#sec-upgrading_to_action_cable
When I get to Step 4, adding ActionCable the chat messages are not transmitted and I get the error:
User Load (0.4ms) SELECT "users".* FROM "users" WHERE "users"."id" IS NULL LIMIT ? [["LIMIT", 1]]
An unauthorized connection attempt was rejected
here are the relevant files:
room_channel.rb:
class RoomChannel < ApplicationCable::Channel
def subscribed
stream_from "room_channel"
end
def unsubscribed
# Any cleanup needed when channel is unsubscribed
end
end
messages controller:
class MessagesController < ApplicationController
before_action :logged_in_user
before_action :get_messages
def index
end
def create
message = current_user.messages.build(message_params)
if message.save
ActionCable.server.broadcast 'room_channel',
message: render_message(message)
message.mentions.each do |mention|
ActionCable.server.broadcast "room_channel_user_# {mention.id}",
mention: true
end
end
end
private
def get_messages
#messages = Message.for_display
#message = current_user.messages.build
end
def message_params
params.require(:message).permit(:content)
end
def render_message(message)
render(partial: 'message', locals: { message: message })
end
end
room.coffee:
App.room = App.cable.subscriptions.create "RoomChannel",
connected: ->
# Called when the subscription is ready for use on the server
disconnected: ->
# Called when the subscription has been terminated by the server
received: (data) ->
# Called when there's incoming data on the websocket for this channel
alert data.content
routes.rb:
Rails.application.routes.draw do
root 'messages#index'
resources :users
resources :messages
get '/login', to: 'sessions#new'
post '/login', to: 'sessions#create'
delete '/logout', to: 'sessions#destroy'
mount ActionCable.server, at: '/cable'
end
The reference branch works fine on my machine, but I can't get my tutorial branch to use AC.
Update:
Skipping down to Section 5 of the tutorial, I added connection.rb, which had been blank in the tutorial's beginning repo as follows:
connection.rb:
module ApplicationCable
class Connection < ActionCable::Connection::Base
include SessionsHelper
identified_by :message_user
def connect
self.message_user = find_verified_user
end
private
def find_verified_user
if logged_in?
current_user
else
reject_unauthorized_connection
end
end
end
end
And broadcasting seems to work in one direction. I have two tabs open. but only one works to broadcast messages. In the other, the console shows this error:
Error: Existing connection must be closed before opening action_cable.self-17ebe4af84895fa064a951f57476799066237d7bb5dc4dc351a8b01cca19cce9.js:231:19
Connection.prototype.open
http://localhost:3000/assets/action_cable.self-17ebe4af84895fa064a951f57476799066237d7bb5dc4dc351a8b01cca19cce9.js:231:19
bind/<
http://localhost:3000/assets/action_cable.self-17ebe4af84895fa064a951f57476799066237d7bb5dc4dc351a8b01cca19cce9.js:201:60
In the logs, with the above connection.rb, the search for null user is gone, showing this:
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]]
Registered connection (Z2lkOi8vY2hhdC1hcHAvVXNlci8x)
RoomChannel is transmitting the subscription confirmation
RoomChannel is streaming from room_channel
Started GET "/cable" for ::1 at 2018-12-29 08:04:31 -0500
Started GET "/cable/" [WebSocket] for ::1 at 2018-12-29 08:04:31 -0500
Successfully upgraded to WebSocket (REQUEST_METHOD: GET, HTTP_CONNECTION: keep-alive, Upgrade, HTTP_UPGRADE: websocket)
I'm having troubles restoring password with devise_token_auth. and Angular2-Token. I'm successfully receiving the email with the link to update my password. But I'm getting an 401 Unauthorized response when submiting the new password.
Front end. I'm getting the token from the URL with urlParams.get('token')
onPasswordUpdate() {
let token = this.urlParams.get('token');
var obj = Object.assign(this._updatePasswordData, { reset_password_token: token })
this._tokenService.patch('auth/password/', obj ).subscribe(
res => res,
error => error
);
}
Back end response.
Started PATCH "/api/auth/password/" for 127.0.0.1 at 2016-12-01 21:17:48 +0100
Processing by DeviseTokenAuth::PasswordsController#update as JSON
Parameters: {"reset_password_token"=>"[FILTERED]", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"}
Completed 401 Unauthorized in 1ms (Views: 0.4ms | ActiveRecord: 0.0ms)
In the link of the email I get the following token : reset_password_token=HneZDoKTMCLF3_SLfnxy
When I visit the link, the user record gets updated with the following attributes :
reset_password_token: "aa3cba76c7b1d8f78cde6856f43e1cce57f5fc8e5301842733de677eff909bc1"
tokens: {}
Then in the browser URL I get the following token=agejaip2SqOp9nvwE1GAHQ&uid
And then the user record get updated with the following attribues :
...
reset_password_token: "HneZDoKTMCLF3_SLfnxy",
tokens: {"pv9i1BDTM29ezep0KSPzpA"=>{"token"=>"$2a$10$cS9gbe9UBICcgphZHRAENOMS6NlEe0Em1cNufY3LSRTPE.hRMabvi", "expiry"=>1481834221}}
...
It seems to me that the token I get back in URL is not correct.
Those anyone have an idea ?
Sorry It's a bit hard to explain.
Many thanks.
rails (4.2.4)
devise_token_auth (0.1.34)
devise (= 3.5.1)
angular2-token: 0.2.0-beta.1
I faced similar challenges recently, and this was how I solved it.
Expose the 'access-token', 'expiry', 'token-type', 'uid', 'client' for your backend. Check here and here
config.middleware.use Rack::Cors do
allow do
origins '*'
resource '*',
:headers => :any,
:expose => ['access-token', 'expiry', 'token-type', 'uid', 'client'],
:methods => => [:get, :post, :options, :delete, :put, :patch]
end
end
Set your redirect_url of path: /password, method: POST. Check info here
We need to modify the reset_password_instructions.html.erb to point it to the api GET /auth/password/edit. More information provided here.
E.g. if your API is under the api namespaces:
<%= link_to 'Change my password', edit_api_user_password_url(reset_password_token: #token, config: message['client-config'].to_s, redirect_url: message['redirect-url'].to_s) %>
I'm writing an app which needs to send many emails and creates many user notifications because of these emails. This task produces a timeout in Heroku. To solve this, I decided to use Resque and RedistToGo.
What I did was to send the email (it's actually just one email because we use Sendgrid to handle this) and create the notifications using a Resque worker. The email is already created, so I send its id to the worker, along with all the recipients.
This works fine locally. In production, unless we restart our app in Heroku, it only works once. I will post some of my code and the error message:
#lib/tasks/resque.rake
require 'resque/tasks'
task "resque:setup" => :environment do
ENV['QUEUE'] = '*'
end
desc "Alias for resque:work (To run workers on Heroku)"
task "jobs:work" => "resque:work"
#config/initalizers/resque.rb
ENV["REDISTOGO_URL"] ||= "redis://redistogo:some_hash#some_url:some_number/"
uri = URI.parse(ENV["REDISTOGO_URL"])
Resque.redis = Redis.new(:host => uri.host, :port => uri.port, :password => uri.password)
Dir["#{Rails.root}/app/workers/*.rb"].each { |file| require file }
#app/workers/massive_email_sender.rb
class MassiveEmailSender
#queue = :massive_email_queue
def self.perform(email_id, recipients)
email = Email.find(email_id.to_i)
email.recipients = recipients
email.send_email
end
end
I've got an Email model which has an after_create that enqueues the worker:
class Email < ActiveRecord::Base
...
after_create :enqueue_email
def enqueue_email
Resque.enqueue(MassiveEmailSender, self.id, self.recipients)
end
...
end
This Email model also has the send_email method which does what I said before
I'm getting the following error message. I'm gonna post all the information Resque gives to me:
Worker
9dddd06a-2158-464a-b3d9-b2d16380afcf:1 on massive_email_queue at just now
Retry or Remove
Class
MassiveEmailSender
Arguments
21
["some_email_1#gmail.com", "some_email_2#gmail.com"]
Exception
ActiveRecord::StatementInvalid
Error
PG::Error: SSL error: decryption failed or bad record mac : SELECT a.attname, format_type(a.atttypid, a.atttypmod), d.adsrc, a.attnotnull FROM pg_attribute a LEFT JOIN pg_attrdef d ON a.attrelid = d.adrelid AND a.attnum = d.adnum WHERE a.attrelid = '"emails"'::regclass AND a.attnum > 0 AND NOT a.attisdropped ORDER BY a.attnum
/app/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.2/lib/active_record/connection_adapters/postgresql_adapter.rb:1139:in `async_exec'
/app/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.2/lib/active_record/connection_adapters/postgresql_adapter.rb:1139:in `exec_no_cache'
/app/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.2/lib/active_record/connection_adapters/postgresql_adapter.rb:663:in `block in exec_query'
/app/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.2/lib/active_record/connection_adapters/abstract_adapter.rb:280:in `block in log'
/app/vendor/bundle/ruby/1.9.1/gems/activesupport-3.2.2/lib/active_support/notifications/instrumenter.rb:20:in `instrument'
/app/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.2/lib/active_record/connection_adapters/abstract_adapter.rb:275:in `log'
/app/vendor/bundle/ruby/1.9.1/gems/newrelic_rpm-3.3.2/lib/new_relic/agent/instrumentation/active_record.rb:31:in `block in log_with_newrelic_instrumentation'
/app/vendor/bundle/ruby/1.9.1/gems/newrelic_rpm-3.3.2/lib/new_relic/agent/method_tracer.rb:242:in `trace_execution_scoped'
/app/vendor/bundle/ruby/1.9.1/gems/newrelic_rpm-3.3.2/lib/new_relic/agent/instrumentation/active_record.rb:28:in `log_with_newrelic_instrumentation'
/app/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.2/lib/active_record/connection_adapters/postgresql_adapter.rb:662:in `exec_query'
/app/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.2/lib/active_record/connection_adapters/postgresql_adapter.rb:1264:in `column_definitions'
/app/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.2/lib/active_record/connection_adapters/postgresql_adapter.rb:858:in `columns'
/app/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.2/lib/active_record/connection_adapters/schema_cache.rb:12:in `block in initialize'
/app/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.2/lib/active_record/model_schema.rb:228:in `yield'
/app/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.2/lib/active_record/model_schema.rb:228:in `default'
/app/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.2/lib/active_record/model_schema.rb:228:in `columns'
/app/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.2/lib/active_record/model_schema.rb:237:in `columns_hash'
/app/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.2/lib/active_record/relation/delegation.rb:7:in `columns_hash'
/app/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.2/lib/active_record/relation/finder_methods.rb:330:in `find_one'
/app/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.2/lib/active_record/relation/finder_methods.rb:311:in `find_with_ids'
/app/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.2/lib/active_record/relation/finder_methods.rb:107:in `find'
/app/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.2/lib/active_record/querying.rb:5:in `find'
/app/app/workers/massive_email_sender.rb:5:in `perform'
According to this, the first argument is the email id, and the second one is the list of all recipients... exactly as it should be.
Can anyone help me? Thanks!
I've run into the same problem. Assuming you're using Active Record you have to call ActiveRecord::Base.establish_connection for each forked Resque worker to make sure it doesn't have a stale database connection. Try putting this in your lib/tasks/resque.rake
task "resque:setup" => :environment do
ENV['QUEUE'] = '*'
Resque.after_fork = Proc.new { ActiveRecord::Base.establish_connection }
end
I tried using this How do I test Pony emailing in a Sinatra app, using rspec? to test a Rails 3.1 app sending emails. The sending works fine, but I'm having a hard time getting the tests to work. Here's what I have so far ...
spec/spec_helper.rb
config.before(:each) do
do_not_send_email
end
.
.
.
def do_not_send_email
Pony.stub!(:deliver) # Hijack to not send email.
end
and in my users_controller_spec.rb
it "should send a greeting email" do
post :create, :user => #attr
Pony.should_receive(:mail) do |params|
params[:to].should == "nuser#gmail.com"
params[:body].should include("Congratulations")
end
end
and I get this ...
Failures:
1) UsersController POST 'create' success should send a greeting email
Failure/Error: Pony.should_receive(:mail) do |params|
(Pony).mail(any args)
expected: 1 time
received: 0 times
# ./spec/controllers/users_controller_spec.rb:121:in `block (4 levels) in '
It looks like Pony's not getting an email, but I know the real email is getting sent out.
Any ideas?
Here's what I finally ended up with for the test ...
it "should send a greeting email" do
Pony.should_receive(:deliver) do |mail|
mail.to.should == [ 'nuser#gmail.com' ]
mail.body.should =~ /congratulations/i
end
post :create, :user => #attr
end
The Pony.should_rececieve needs :deliver (not :mail), the do/end was changed a bit, and the post was done after the setup.
Hope this helps someone else.
I know this is an old question but there is another way to test this. Version 1.10 of Pony added override_options. Pony uses Mail to send email. override_options lets you use the TestMailer functionality that is built into Mail. So you can set up your test like this:
In spec_helper
require 'pony'
Pony.override_options = { :via => :test }
In your test
before do
Mail::TestMailer.deliveries.clear
end
it 'some test' do
# some code that generates an email
mail = Mail::TestMailer.deliveries.last
expect(mail.to).to eql 'some#email.com'
end
I'm following Railscast #199 to allow my web app to be viewed in a mobile browser. It works great, except when I try to access information in a tabbed interface using UJS in the mobile version. Clicking on the tabs works in the web app, but on the mobile side I get a 406 error. (I tried this after setting the User Agent as iPhone in Safari. I also tested on iOS Simulator and my iPhone. Neither time loaded anything.)
Below is some code for one of the tabs. Can anyone can help me target what is going on? Here is my code.
Here's the profile_about action in profiles_controller.rb:
def profile_about
#profile = Profile.find(params[:id])
respond_to do |format|
format.js { render :layout => nil }
end
end
In my profiles/show.mobile.erb (this is the exact same code as in profiles/show.html.erb):
<div id="tabs">
<ul id="infoContainer">
<li><%= link_to "Cred", profile_cred_profile_path, :class=> 'active', :remote => true %></li>
<li><%= link_to "About", profile_about_profile_path, :class=> 'inactive', :remote => true %></li>
</ul>
<div id="tabs-1">
<%= render :partial => 'profile_cred' %>
</div>
</div><!-- end tabs -->
(NOTE: I have a file for profiles/_profile_about.html.erb and profiles/_profile_about.mobile.erb.)
Here is my profiles/profile_about.js.erb:
$("#tabs-1").html("<%= escape_javascript(render(:partial => 'profile_about'))%>");
My Heroku logs showing the 406:
2012-03-08T03:02:55+00:00 app[web.1]: Started GET "/profiles/1/profile_about" for 98.218.231.113 at 2012-03-08 03:02:55 +0000
2012-03-08T03:02:55+00:00 heroku[router]: GET myapp.com/profiles/1/profile_about dyno=web.1 queue=0 wait=0ms service=14ms status=406 bytes=1
2012-03-08T03:02:55+00:00 app[web.1]: Processing by ProfilesController#profile_about as JS
2012-03-08T03:02:55+00:00 app[web.1]: Parameters: {"id"=>"1"}
2012-03-08T03:02:55+00:00 app[web.1]: Completed 406 Not Acceptable in 3ms
2012-03-08T03:02:55+00:00 heroku[nginx]: 98.218.231.113 - - [08/Mar/2012:03:02:55 +0000] "GET /profiles/1/profile_about HTTP/1.1" 406 1 "http://myapp.com/profiles/1" "Mozilla/5.0 (iPhone; CPU iPhone OS 5_0_1 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Mobile/9A405 Safari/7534.48.3" myapp.com
From running tail -f logs/development.log:
Started GET "/profiles/1/profile_about" for 127.0.0.1 at Wed Mar 07 22:35:36 -0500 2012
Processing by ProfilesController#profile_about as JS
Parameters: {"id"=>"1"}
PK and serial sequence (5.4ms) SELECT attr.attname, seq.relname
FROM pg_class seq,
pg_attribute attr,
pg_depend dep,
pg_namespace name,
pg_constraint cons
WHERE seq.oid = dep.objid
AND seq.relkind = 'S'
AND attr.attrelid = dep.refobjid
AND attr.attnum = dep.refobjsubid
AND attr.attrelid = cons.conrelid
AND attr.attnum = cons.conkey[1]
AND cons.contype = 'p'
AND dep.refobjid = '"goals_profiles"'::regclass
PK and custom sequence (2.5ms) SELECT attr.attname,
CASE
WHEN split_part(def.adsrc, '''', 2) ~ '.' THEN
substr(split_part(def.adsrc, '''', 2),
strpos(split_part(def.adsrc, '''', 2), '.')+1)
ELSE split_part(def.adsrc, '''', 2)
END
FROM pg_class t
JOIN pg_attribute attr ON (t.oid = attrelid)
JOIN pg_attrdef def ON (adrelid = attrelid AND adnum = attnum)
JOIN pg_constraint cons ON (conrelid = adrelid AND adnum = conkey[1])
WHERE t.oid = '"goals_profiles"'::regclass
AND cons.contype = 'p'
AND def.adsrc ~* 'nextval'
Profile Load (1.3ms) SELECT "profiles".* FROM "profiles" WHERE "profiles"."id" = '1' LIMIT 1
Completed 406 Not Acceptable in 30ms
There's a few bugs in your code, maybe it's just stackoverflow formatting here but the inner quotes should be ' instead of " , like this:
$("#tabs-1").html("<%= escape_javascript(render(:partial => 'profile_about'))%>");
And this line is casuing your error:
format.mobile.js {render :layout => nil}
This is impossible because the request can only have a single mime type. "mobile" or "js", not both. If you are requesting the "profile_about" action from javascript, then you must respond back to it with js. "format.mobile" should only be used to render a "profile_about.mobile" template.
Hopefully that's at least a step in the right direction for you.
Probably don't fully answer your question but I was having the 406 status problem, because I've been deploying my app to Phonegap!
It basically happened because the request type didn't match any of the Rails responders in the action.
it was like:
respond_to do |format|
format.json {
render( json: (#parishes) )
}
end
Since I only used it to responde to JSON I changed and it now works:
render( json:(#parishes) )
A more complete way to deal with this is to figure exactly what responder is being asked for that request, or default to something you know to work
Turns out this was due to a lacking check for an xhr request in the prepare_for_mobile method. I found the answer in another question. So the below prepare_for_mobile method allows the JS to work:
def prepare_for_mobile
session[:mobile_param] = params[:mobile] if params[:mobile]
request.format = :mobile if mobile_device? && !request.xhr?
end