我需要在Rails 3控制器中处理传入的电子邮件并将其插入数据库?

时间:2011-03-21 18:16:49

标签: ruby ruby-on-rails-3 email

我正在尝试设置我的RoR 3应用程序来接收电子邮件,然后处理这些电子邮件并将其插入数据库。

在我的应用程序中,我有一个“作业”控制器。用户可以创建工作。我也有一个“评论”控制器。用户可以创建有关作业的评论。

以下是我在评论控制器中的部分内容:

def new
  @job = Job.find(params[:job_id])
  @comment = @job.comments.build
end

def create
  @job = Job.find(params[:job_id])
  @comment = @job.comments.build(params[:comment])
  @comment.user_id = current_user.id
  @comment.commenter = current_user.login
 if @comment.save
    redirect_to @job
  else
    render :action => "new"
 end
end

当用户添加评论时,管理员会收到一封电子邮件。 当管理员添加评论时,用户会收到一封电子邮件。 (这已经在运作了。)

我正在使用Cloudmailin来帮助我接收收到的邮件。我已将Cloudmailin地址设置为指向http://myapp.com/incoming_mails

class IncomingMailsController < ApplicationController

  require 'mail' 
  skip_before_filter :verify_authenticity_token

    def create
      another_comment = Comment.create(:title => 
      params[:subject], :body => params[:plain])

      render :text => 'success', :status => 200 #status of 404 rejects mail

    end
end

查看上面的注释控制器,看起来我需要job_id,current_user.id和current_user.login。

这是我在排序时遇到的问题:我的“incoming_mails”控制器中有什么内容?当用户通过电子邮件响应“incoming_mails”中的控制器能够找到job_id和current_user.id(或user_id)然后将该信息插入数据库时​​,如何确保?

我想我需要抓住用户的电子邮件地址,然后在主题行中也有job_id ......嗯......

有没有人有在Rails 3中设置传入邮件处理的经验?

2 个答案:

答案 0 :(得分:3)

有几种方法可以做到这一点。一种常见的技术是将from / reply_to设置为自定义电子邮件地址,以允许您查找原始对象。类似的东西:

 class Comment < ActiveRecord::Base
   belongs_to :commentable
   has_many :comments, :as => :commentable
   before_validation :generate_token, :on => :create

   validates :token, :presence => true, :uniqueness => true
   attr_accessible :token

   private

   def generate_token
     ...
   end
 end

电子邮件发送时带有来自/ reply_to的地址,如[token] @ msg.yoursite.com (如果您愿意,也可以使用评论+ [token_or_id] @ msg.yoursite.com - 请参阅:cloudmailin提供的:一次性param)

 class IncomingMailsController < ApplicationController

   def create
     @comment = Comment.find_by_token(params[:to].split('@')[0])
     @comment.comments.create(:body => params[:plain])
     render :text => 'success', :status => 200
   end
 end

如果您使用[token] @ msg.yoursite.com,则必须按照here所述正确设置您的DNS记录。

另一种选择是将内容存储在电子邮件的标题中。也许你的标题看起来像这样:

 X-YOURAPP-OBJECT-ID = 44
 X-YOURAPP-OBJECT-TYPE = Job
 X-YOURAPP-TARGET-ASSOC = comments
 X-YOURAPP-TARGET-ATTR = body

然后你的控制器会更像这样:

 class IncomingMailsController < ApplicationController

   def create
     headers = Mail::Header.new(params[:message])
     object= headers[:x_yourapp_object_type].constantize.find(headers[:x_yourapp_object_id])
     object.send(headers[:x_yourapp_target_assoc]).create(headers[:x_yourapp_target_attr] => params[:plain])
     render :text => 'success', :status => 200
   end
 end

这样做的好处是它完全通用。您可以对工作,评论评论或其他任何内容发表评论。如果您创建另一个模型,您还希望允许电子邮件回复...只需更新标题即可进行设置。唯一的问题是你必须小心邮件客户端剥离这些标题。有关详细信息,请查看this thread

我目前正在使用第一种技术并且它运行良好。但是,我将在本周末重构并尝试第二种技术。

答案 1 :(得分:1)

我不确定这是一个完整的答案,但是让我快速给出它,当我有更多的时间时我可以更新它。

首先,我首先要将这项工作作为解决方案的一部分。使用comment+1@domain.com,表示这是第一个作业。这个部分在加之后被称为是CloudMailin中的一次性部分(params [:disposable]。然后可以使用params [:from]或Mail.new(params [:message])从邮件正文中获取用户的电子邮件地址。 ).from(有时提供给SMTP服务器的地址与标题中的地址不同)

接下来你有评论本身,它可以简单地作为普通的参数。

这给出了如下内容:

def create
  @job = Job.find(params[:disposable])
  if comment = @job.comments.create(:text => params[:plain], :commenter => User.find_by_email(params[:from])
    render :text => 'Success', :status => 401
  else
    render :text => comment.errors.inspect, :status => 422, :content_type => 'text/plain'
 end

我希望有所帮助。这有点粗糙,但希望它给出了正确的想法。