views:

163

answers:

3

I'd like to send emails from a table every night at midnight, so I've created a model to track all communications to be sent. This Communication model stores who the letter is to, from, and the contents of the letter to be sent as html. The user enters a criteria to match for whom the letter is intended: state, country, favorite color, and so which returns a list of acceptable matches.

This list of acceptable matches is iterated across and a new Communication is generated for each. How do I render the contents of a partial view to a string to store in the database for delivery at midnight.

@communication = Communication.new(params[:communication])
@communication.body = //Render Partial with local variables to string here

January 8, 2010: I've implemented the solution proposed by neutrino, and my code looks like this:

@communication.message_body = render_to_string(
  :partial => "letters/small_letter", 
  :locals => { :quote => @quote})

The drawback to this approach is that it requires a context so it must be rendered within a controller, this rules out generating the email using a rake file. As others have pointed out the approach of using a Communication model may introduce some unnecessary complexity. At this time since the conditions I use to generate the list of recipients is never stored I've opted to continue to use a communication model.

+1  A: 

As (almost) always in Rails, there's a method for that :) - ActionController::Base#render_to_string

Apidock docs

neutrino
This requires having an active view context, as far as I know, and doesn't work for rake tasks, among other things.
tadman
I'm rendering the partial from the Communication controller, and I therefore have a context. This solution works wonderfully, thank you.
nixterrimus
A: 

Have you tried action mailer? It will get your views rendered and provide active record support also.

Nakul
+3  A: 

You may want to look at techniques to render a template outside of a controller, such as:

http://www.swombat.com/rails-rendering-templates-outside-of-a-contro

That being said, it's probably better to make use of the built-in email sending class ActionMailer::Base which can render templates for you. Storing the parameters in your Communication model is probably better than storing your unrolled HTML, as these parameters can be serialized and later pushed back into a "send_X_notification" type call.

These can be built using the generator:

script/generate mailer communications_mailer
tadman
Yep, that's a better answer
neutrino
Thank you, this looks excellent. My thought with the Communication model was that it would make it easy for me to create a large number of emails that need to be sent and then wait to send them until a specified time like midnight. Would it make sense to use both my communication model and Action Mailer?
nixterrimus
+1 for using ActionMailer for emailing!You may want to look into background job control if you are planning on doing things asynchronously, for example delayed_job
jamuraa
There's nothing wrong with using a model to intermediate the sending of email. In fact, on some occasions it's actually a lot more efficient since you only need to iterate over some simple models rather than the original set which may be considerably larger. I would evaluate, though, if the additional complexity of the Communication model is worth the trouble compared to simply sending the messages using the Notifier directly.
tadman
Thank you for your thoughts, tadman. Since the conditions I use to find the group of people to whom to send the communications is never stored, I think that in this case it is more efficient to generate the complete letter and then send it later rather than having to sore how to find the recipients. I appreciate your perspective and the confidence it gives me that I'm doing the right thing.
nixterrimus