31

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.

4 Answers 4

39

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

In Rails 3, this method was moved to AbstractController::Rendering#render_to_string.

Sign up to request clarification or add additional context in comments.

4 Comments

This requires having an active view context, as far as I know, and doesn't work for rake tasks, among other things.
I'm rendering the partial from the Communication controller, and I therefore have a context. This solution works wonderfully, thank you.
looks like the method is deprecated
@avioing The one in ActionController::Base was deprecated, but they really just moved it to AbstractController::Rendering.
12

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

http://geek.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

4 Comments

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?
+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
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.
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.
5

you could try this (in the rails console):

  class StaticRender < ActionController::Base
    def self.render_erb(template_path, params)
      view = ActionView::Base.new(ActionController::Base.view_paths, {})
      class << view
        include ApplicationHelper
      end
      view.render(:file => "#{template_path}.html.haml", :locals => params, :layout => false)
    end
  end


 StaticRender.render_erb("home", {})

you need to have the view "home" for that....

Comments

0

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.