I am running a rails app on heroku and would like to send an email to 160 users. This is the first time I am doing this so I would to very whether the method below will lead to a successful outcome.
Sendgrid is all sent up and I have a controller setup that executes the following:
#users = User.all
#users.each do |u|
Email.send_email(p).deliver
end
I am assuming that since the number of recipients is relatively low I would be able to get by without using delayed_job or some other background processing.
SendGrid actually makes it easy to send out emails without having to use a background worker. You can do it using the X-SMTPAPI header and setting an array of email addresses in the to field. For example:
X-SMTPAPI: {
to: ["john.doe#example.com", "jackson#example.com", "freddy#example.com"]
}
In this example, each of these three emails will receive a separate copy of the email. No background workers, no complexity.
There's a gem called sendgrid that does a good job of adding some useful helpers to action mailer. Have a look at the "multiple recipients" section of the README
https://github.com/stephenb/sendgrid
I would advise that you invest the time into some background processing, as this could potentially be a hit or miss, all depending on the emailing service.
Related
I'm trying to save email to a database, to send it later via a rake task. It was pretty easy in rails 2.3.8 (TMail), but I'm having trouble with rails 3.2.
Once I get the Mail object (mail), I call mail.encoded to serialize the email. I save this to the database.
My rake task loads the encoded message, but I can't find a way to recreate the mail object and call deliver (deserialize).
Mail.new(mail.encoded) seems like it should work, but the delivery fails because Mail.new doesn't get the default ActionMailer SMTP settings.
Anyone else doing something like this?
Thanks!
Alright, got this working.
To serialize the email I do the following.
email = mail(:to => 'to#me.com', ....)
string = mail.encoded
# later one
mail.new(email.string)
Mail.deliver(mail)
This appears to skip any HTML validation.
I can't set the Mail send settings (SMTP, etc), but I think it defaults to :sendmail, and that's working on the web server.
I've been seeing some interesting behavior with the Instagram gem and realtime API, I am trying to create a basic app to create subscriptions and process Instagrams' response. Below is the code to create the subscription and save the tag name to my db.
def create
#subscription = Subscription.new params[:subscription]
options = {:object_id => params[:subscription][:tag_name]}
if #subscription.save
Instagram.create_subscription('tag', "http://myapp.herokuapp.com/subscriptions/process_subscription/", aspect = 'media', options)
redirect_to "/subscriptions/tag/#{#subscription.tag_name}"
end
Notice the callback url is at heroku which is reachable, the interesting thing is that when I go to subscriptions/new at the heroku domain the Instagram API gives me a "Bad Request, Unable to reach callback URL". When I create the subscription over curl with the same callback url everything works as expected, when I go to subscriptions/new on my localhost (with the same callback url set) it also works as expected. Below is the process_subscription action:
def process_subscription
if params["hub.challenge"]
render :text => params["hub.challenge"]
else
PrivatePub.publish_to("/subscriptions/tag/#{params[:object_id]}", payload: params[:_json])
end
end
The first if statement will take care of the pubsubhubub challenge. Once the subscription is actually created I don't have a problem receiving and processing the payload. So right now the only thing I can think of is when i'm at the heroku domain the server process is somehow busy when Instagram posts back to it, I don't understand how that would be possible so any advice would be greatly appreciated.
Here is a link to the server logs when a subscription is successful and when it fails. Note, I was logging out the post params in these logs. https://gist.github.com/4256108.
After much trial and error, the problem was looking more and more like the rails process was busy when Instagram sent its' hub.challenge back to the app resulting in the "Bad Request, Unable to reach callback URL" error.
What worked for me was using another thread to create the Instagram subscriptions, this way Instagram can successfully hit my app almost instantaneously and reach my callback url. This solution was the quickest and most lightweight, perhaps It would be beneficial to purchase one or so workers on Heroku and move this into a background process via Sidekiq or something but that seems a bit overkill for just responding to a hub challenge.
def instagram_photos
Thread.new do |t|
options = {:object_id => params[:tag_name]}
Instagram.create_subscription('tag', "http://myapp.herokuapp.com/subscriptions/process_subscription", aspect = 'media', options)
t.exit
end
redirect_to root_path
end
I'm building an audit trail that needs to know which user is currently making the request. My audit trail is built using ActiveSupport::Notifications to receive an even that needs to be audited.
What I would like to do is use an ActiveSupport::Concern to encapsulate the logic for my audit needs, so that I can easily add auditing to any model in my system.
In general this is easy to do. I even blogged about it a while back. However, I'm having a hard time figuring out how to get the current user that making the request to the web server, so that I can log who is making what changes in my audit trail.
I know there are a ton of questions about "how do I get current_user in my model" but I'm not asking about doing it in a model, so I'm hoping there is a better set of answers. Since my audit code is infrastructure related, I am hoping that there is some way I can tap into the current request that is being processed, or something else that would definitively tell me who is currently logged in / making the request.
I've read a lot of "answers" that say to use thread storage and put the current_user in there. I don't like this answer for many of the reasons that others don't - there is no guarantee that thread storage is safe. it could bleed across multiple requests if the server uses the same thread to process multiple requests, etc.
so... given that I am not trying to access current_user from my model, but rather from either an ActiveSupport::Concern or ActiveSupport::Notifications event subscription, are there any good options for me to know who the current user is?
Update
I'm using devise for authentication, which uses Warden on the back end. devise retrieves the current_user by calling request.env['warden'].authenticate(:scope => :user) (assuming i use a "User" model for authentication).
Is there a way for me to access the current request object from within my concern or notification subscription? Back in my .NET days, I would have been able to call HttpContext.Current.Request and all would be good. What's the equivalent in Rails?
Rails' ActionController::Instrumentation has explicit support for this, using append_info_to_payload.
Add a method to your ApplicationController:
def append_info_to_payload(payload)
super
payload[:current_user_id] = current_user.try(&:id)
end
now, when your observer is called back, the information will be in the event.payload:
ActiveSupport::Notifications.subscribe /process_action.action_controller/ do |*args|
event = ActiveSupport::Notifications::Event.new(*args)
current_user_id = event.payload[:current_user_id]
# do something interesting with current_user_id here
end
You already have the answer, what you're doing is the same as when people are accessing the request in models. The current_user is just a method defined on your ApplicationController. When you're not in a controller or other class that inherits from it, you can't access that method.
HttpContext.Current.Request << I would bet a lot that this uses thread storage. Any other solution we find will also be thread storage at some level or another.
Either pull out what you need from the request in the controller and pass it down as parameters, or use thread storage -- but this is inherently dangerous anyway. What if you start using delayed job to do the notifications or something?
I need a way to implement deferred FTP uploads, to different servers, in a Rails3 application. This will be the scenario:
The user builds a folder full of files and subfolders, with a simple Rails3 CMS (DONE)
When the user ends his work, he would click on a deploy button.
The system takes the control and stores the user request.
The systen gives the control back to the user, this way he can work on other stuff.
At the same time the system initiates 10 FTP uploads of the same folder.
When an upload ends it will store its status somewhere.
The user can see the deployment status, at any time, by going on a specific page.
Uploaded folders size will be from 600Mb to 1Gb. They will contain PNG images, little mp4 movies and xml files.
The web server and all the ftp server will be on the same network, same subnet. No need of extra security for now.
I'm completely new to asynchronous or delayed jobs. The application will have just one or two users: no need to handle a lot of deploy requests at the same time.
How can I accomplish this task? If you need more info please ask in the comments.
Once you have delayed_job set up, you can set a method to perform in the background while you go about your business. In this case, the deploy method would always be in the background–set by handle_asynchronously.
class UploadStatus < ActiveRecord::Base
def deploy
# write your ftp loop here
# periodically update this model in the db with the status
end
handle_asynchronously :deploy
end
Now, you can just call #upload_status.deploy() and it will run in the background.
You could also write a job method, but I think that it makes more sense in an ActiveRecord class because you will be updating the deploy status.
I need some help figuring out the best way to proceed with creating a Rails 3 engine(or plugin, and/or gem).
Apologies for the length of this question...here's part 1:
My company uses an email service provider to send all of our outbound customer emails. They have created a SOAP web service and I have incorporated it into a sample Rails 3 app. The goal of creating an app first was so that I could then take that code and turn it into a gem.
Here's some of the background: The SOAP service has 23 actions in all and, in creating my sample app, I grouped similar actions together. Some of these actions involve uploading/downloading mailing lists and HTML content via the SOAP WS and, as a result, there is a MySQL database with a few tables to store HTML content and lists as a sort of "staging area".
All in all, I have 5 models to contain the SOAP actions (they do not inherit from ActiveRecord::Base) and 3 models that interact with the MySQL database.
I also have a corresponding controller for each model and a view for each SOAP action that I used to help me test the actions as I implemented them.
So...I'm not sure where to go from here. My code needs a lot of DRY-ing up. For example, the WS requires that the user authentication info be sent in the envelope body of each request. So, that means each method in the model has the same auth info hard coded into it which is extremely repetitive; obviously I'd like for that to be cleaner. I also look back now through the code and see that the requests themselves are repetitive and could probably be consolidated.
All of that I think I can figure out on my own, but here is something that seems obvious but I can't figure out. How can I create methods that can be used in all of my models (thinking specifically of the user auth part of the equation).
Here's part 2:
My intention from the beginning has been to extract my code and package it into a gem incase any of my ESP's other clients could use it (plus I'll be using it in several different apps). However, I'd like for it to be very configurable. There should be a default minimal configuration (i.e. just models that wrap the SOAP actions) created just by adding the gem to a Gemfile. However, I'd also like for there to be some tools available (like generators or Rake tasks) to get a user started. What I have in mind is options to create migration files, models, controllers, or views (or the whole nine yards if they want).
So, here's where I'm stuck on knowing whether I should pursue the plugin or engine route. I read Jordan West's series on creating an engine and I really like the thought of that, but I'm not sure if that is the right route for me.
So if you've read this far and I haven't confused the hell out of you, I could use some guidance :)
Thanks
Let's answer your question in parts.
Part One
Ruby's flexibility means you can share code across all of your models extremely easily. Are they extending any sort of class? If they are, simply add the methods to the parent object like so:
class SOAPModel
def request(action, params)
# Request code goes in here
end
end
Then it's simply a case of calling request in your respective models. Alternatively, you could access this method statically with SOAPModel.request. It's really up to you. Otherwise, if (for some bizarre reason) you can't touch a parent object, you could define the methods dynamically:
[User, Post, Message, Comment, File].each do |model|
model.send :define_method, :request, proc { |action, params|
# Request code goes in here
}
end
It's Ruby, so there are tons of ways of doing it.
Part Two
Gems are more than flexible to handle your problem; both Rails and Rake are pretty smart and will look inside your gem (as long as it's in your environment file and Gemfile). Create a generators directory and a /name/name_generator.rb where name is the name of your generator. The just run rails g name and you're there. Same goes for Rake (tasks).
I hope that helps!