tonypm
2008-Jan-02 22:25 UTC
how to replace keywords with values to merge into an email template
I am making an email template system, in which certain keywords are to be replaced by values from the model. eg {ORDERNO}, {NAME} etc My plan is to do the following. 1. find all keywords in the text (subject and body as separate methods) 2. check all keywords are valid (from a predefined list) 3. go through each keywords found and use gsub to substitute them 4. identify any non valid keywords and make them available to the calling method 5. return the text after substitution I thought that maybe if I put any invalid keys into an attribute hash, :invalid_keywords, that can be checked by the calling method. I cannot think of the best approach to solve step 1. My immediate approach would be to recursively find each keyword in turn, recursing through the remaining string. I feel there is a neat way to write this (or can it be done directrly with regexp). Grateful for suggestions here. Also, it seems to me that Rails must do similar sorts of things - I wonder if there is a better overall approach, or something in Rails that will help in achieving the overall requirement. Thanks for any advice Tonypm --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
Rick DeNatale
2008-Jan-02 23:24 UTC
Re: how to replace keywords with values to merge into an email template
On Jan 2, 2008 5:25 PM, tonypm <tonypmartin-PkbjNfxxIARBDgjK7y7TUQ@public.gmane.org> wrote:> > I am making an email template system, in which certain keywords are to > be replaced by values from the model. eg {ORDERNO}, {NAME} etc > > My plan is to do the following. > > 1. find all keywords in the text (subject and body as separate > methods) > 2. check all keywords are valid (from a predefined list) > 3. go through each keywords found and use gsub to substitute them > 4. identify any non valid keywords and make them available to the > calling method > 5. return the text after substitution > > I thought that maybe if I put any invalid keys into an attribute > hash, :invalid_keywords, that can be checked by the calling method. > > I cannot think of the best approach to solve step 1. My immediate > approach would be to recursively find each keyword in turn, recursing > through the remaining string. I feel there is a neat way to write > this (or can it be done directrly with regexp). Grateful for > suggestions here. > > Also, it seems to me that Rails must do similar sorts of things - I > wonder if there is a better overall approach, or something in Rails > that will help in achieving the overall requirement.Ummmm, it sounds to me as though you are trying to write a replacement for ActionMailer. Why? -- Rick DeNatale My blog on Ruby http://talklikeaduck.denhaven2.com/ --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
tonypm
2008-Jan-04 15:26 UTC
Re: how to replace keywords with values to merge into an email template
> Ummmm, it sounds to me as though you are trying to write a > replacement for ActionMailer. Why? > > -- > Rick DeNatale > > My blog on Rubyhttp://talklikeaduck.denhaven2.com/Rick, I am using actionmailer to create and deliver the email. When the email is created, the user is able to choose from one of a set of user templates from a model email_template. The template has a name, and defines text for subject and body. Within the template, the user is able to include fields which are to be substituted with things like customer name, order number, order details etc. He can insert these into the template so that he gets a form of mail merge. So when the email is being created, the user selects the email template by name from a select drop down. This then updates the page with the text from the template. At this point I want to substitute in the mail merge values before the text is displayed. I was working on the premise that I would have to do the substiutions fo the fields for the tags. But I may be missing something that AcionMailer can do for me Thanks Tony --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
Phillip Koebbe
2008-Jan-04 16:34 UTC
Re: how to replace keywords with values to merge into an email template
Hi Tony, I had to do something similar a couple of months ago, and I tackled it like this: I created a module that defined an array of hashes which represented the supported tags. Here are some examples: tags << { :find => ''order.id'', :verify => ''id'', :replace => ''id.to_s'', :default => '''', :description => ''The ID of the order.'', :domain => ''Orders'' } tags << { :find => ''order.status'', :verify => ''status'', :replace => ''status.name'', :default => '''', :description => ''The status of the order.'', :domain => ''Orders'' } tags << { :find => ''order.user.name'', :verify => ''user'', :replace => ''user.name'', :default => '''', :description => ''The name of the user who submitted the order.'', :domain => ''Orders'' } and then to make parsing a little easier, wrap each "find" in some kind of marker tags.each do |tag| tag[:find] = "{t:#{tag[:find]}}" end this happens to be similar to RadiantCMS''s style, so your the tag in text will look like Hi {t:order.user.name}, your order shipped on {t:order.shipped}. I included "description" and "domain" for building a small help popup for the user when inserting tags. I had tags in two main domains, Users and Orders, but this way I could add whatever else I needed. Now, to parse these, I came up with this method: def TemplateTags.replace_tags(object, template, content = nil) tags = supported_tags # this method returns the array of support tags tags.each do |tag| find = tag[:find] replace = tag[:replace] verify = tag[:verify] default = tag[:default] if find.include?(''content'') if content template.gsub!(find, content) end elsif replace begin replace = if object.instance_eval(verify) then object.instance_eval(replace) else default end rescue replace = default end template.gsub!(find, replace) end end return template end To this, you pass an object (order, user, whatever), the template (with all of the tags), and, in my case, an optional "content". Content was something that the system needed to put in, and it''s template tag was defined as tags << { :find => ''content'', :verify => nil, :replace => nil, :default => nil, :description => ''Place holder for system generated messages.'', :domain => ''Orders'' } This is kind of a kludge, because the user had to know to put {t:content} in their template. But in the particular case in which this was implemented, that was a reasonable request. The trick to this is verifying that the object can actually respond to the method that you might want to call on it, which is the purpose of if object.instance_eval(verify) Essentially what you are doing is saying "check to see if the object has <verify>, and if it does, then ask it for <replace>". Two examples are the tags noted above, order.id and order.status. First, order.id: the template will look like this: "Your order, id #{t:order.id}, shipped yesterday" so in the code, you pass an order object to replace_tags. replace_tags needs to make sure that object can respond to id, and if it can, it calls id. So in this case you are doing something like if object responds id, then call id In the second example, order.status, my status was an association, so to get to it normally, you''d use order.status.name. The tag would look like "Your order is now {t:order.status}" so in replace_tags, I first had to check to see if the object had the proper association, which is the verify: if object responds to status, call status.name I hope that makes sense. This is the first time I''ve had to try to explain it to anyone, and typing it out at that! To sit down with someone and explain it would, I think, be much easier. I also admit that this might not be the best way to address this problem, but this worked for what I needed. The main downside is you have to create an array of hashes that represent all of the tags you support, but I don''t know how to get around that. Let me know if you have any questions. I can create a small working example if you need me to. Peace, Phillip On Jan 4, 2008, at 9:26 AM, tonypm wrote:> > > >> Ummmm, it sounds to me as though you are trying to write a >> replacement for ActionMailer. Why? >> >> -- >> Rick DeNatale >> >> My blog on Rubyhttp://talklikeaduck.denhaven2.com/ > > Rick, > > I am using actionmailer to create and deliver the email. When the > email is created, the user is able to choose from one of a set of user > templates from a model email_template. The template has a name, and > defines text for subject and body. Within the template, the user is > able to include fields which are to be substituted with things like > customer name, order number, order details etc. He can insert these > into the template so that he gets a form of mail merge. > > So when the email is being created, the user selects the email > template by name from a select drop down. This then updates the page > with the text from the template. At this point I want to substitute > in the mail merge values before the text is displayed. > > I was working on the premise that I would have to do the substiutions > fo the fields for the tags. But I may be missing something that > AcionMailer can do for me > > Thanks > Tony > >--~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
Thorsten Mueller
2008-Jan-04 16:59 UTC
Re: how to replace keywords with values to merge into an ema
maybe you could use ERB manually to do the job. it offers a few options to do things like that (eg changing the the type of recognized tags and how it''s handling the usage of local variables when resolving the template). http://www.ruby-doc.org/core/classes/ERB.html -- Posted via http://www.ruby-forum.com/. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
tonypm
2008-Jan-17 08:47 UTC
Re: keyword replace - using instance_eval. How to also use erb for a merge of a :partial ?
Phillip/Thorsten, Have just got back onto this project. Thank you both for your responses, both have merit. I was not aware of instance_eval and that makes generalizing the solution really nice (the thing I really like about Ruby). My template requirement is fairly simple and is now working. I may also employ the erb solution, since one of the replacements may work best as a partial, since I may want to expand a single keyword into multiple order details. I figure if I make the first replacement say {ORDERDETAILS} to become <%= render :partial=>''order_details'' %> and then run the result through erb, I will get quite a neat solution. I have put the initial keyword replacement stuff into the email template model and that works quite nicely, though at the moment, I think I will need to do the pass through erb from the controller. Still trying to get my head fully around setting up an erb template at the moment though. If anyone could suggest a simple bit of code to include in my controller I would be grateful. If I have the string containing the < %= render .... line, and I have the object @order in the controller from which I can derive everything for the partial, I just need the code to call erb with the string and the @order object. (I am not sure what the ''binding'' thing is all about and whether I would need it. Many thanks Tonypm --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
Phillip Koebbe
2008-Jan-17 12:34 UTC
Re: keyword replace - using instance_eval. How to also use erb for a merge of a :partial ?
On Jan 17, 2008, at 2:47 AM, tonypm wrote:> > Phillip/Thorsten, > > Have just got back onto this project. Thank you both for your > responses, both have merit. I was not aware of instance_eval and that > makes generalizing the solution really nice (the thing I really like > about Ruby). >After I sent that message, I got to thinking that this approach might also work with respond_to? instead of instance_eval. It might be a little simpler that way. I''m not sure.> My template requirement is fairly simple and is now working. I may > also employ the erb solution, since one of the replacements may work > best as a partial, since I may want to expand a single keyword into > multiple order details. I figure if I make the first replacement say > {ORDERDETAILS} to become <%= render :partial=>''order_details'' %> and > then run the result through erb, I will get quite a neat solution. >When I created my little "engine", I considered the possibility of needing to do this. Fortunately (or not, depending on how you look at it), I didn''t have an actual need at the time, so I didn''t push forward. However, just bouncing it around quickly right now, it might be possible to use the concept of "content" that I have. The downside is that you''d have to know ahead of time which partials you''d need to generate for a particular template. But if that were possible, you could do something like partial_output = render_to_string :partial => ''order_details'', :locals => {:collection => order_details) template_output = TemplateEngine.replace(order, template, partial_output) I''m sure it would have some kinks to work out, but I bet you could do it. If I ever come across a need, I''ll probably do it. Peace, Phillip --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
tonypm
2008-Jan-22 18:36 UTC
Re: keyword replace - using instance_eval. How to also use erb for a merge of a :partial ?
I have just come back to this one to try to solve the partial issue.> partial_output = render_to_string :partial => > ''order_details'', :locals => {:collection => order_details) > template_output = TemplateEngine.replace(order,template, > partial_output)What you suggest is helpful. Since I am only likely to have one partial, I can do that. Render the partial into a string before I do the tag replacement and pass that into the replacement method. Excellent! Many thanks for your suggestions. Tony --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---