Rails 3.2`link_to`(在电子邮件中)与`method :: put`仍然产生GET请求

时间:2014-08-29 17:10:08

标签: ruby-on-rails ruby email http hyperlink

在我的应用程序中,我有自动电子邮件提醒应用程序完成面试过程的下一步。电子邮件有一个退出链接,当单击该链接时,应该触发一个控制器操作,该操作会触发状态机事件以将其状态更改为opted_out。链接不起作用,并且从localhost控制台看起来似乎是因为链接仍然产生GET请求,没有路由(错误是ActionController::RoutingError (Not Found):)。

以下是显示不需要的GET请求的控制台:

Started GET "/worker/application/opt_out.1" for 10.0.2.2 at 2014-08-29 17:08:06 +0000
Processing by LandingController#show as 
  Parameters: {"category"=>"worker/application", "location"=>"opt_out"}

这是链接:

link_to 'stop getting these reminders', opt_out_worker_application_url(@worker), method: :put, style: 'background-color: #fff; color: #56A0D3; display: inline-block; margin-bottom: 5px; margin: 0px; padding: 0px; text-decoration: none'

以下是worker命名空间的所有路由:

# routes.rb

  namespace :worker do
    resource :application, only: [:create, :new, :show] do
      member do 
        put 'opt_out' => 'application#opt_out'
      end
    end
    resources :jobs do
      member do
        post 'compete' => 'jobs#compete'
        delete 'compete' => 'jobs#withdraw'
      end
      resources :comments, only: [:create]
      resources :timesheets, only: [:create, :new, :show]
    end
    resources :banks, only: [:create, :new, :destroy]
    scope 'money' do
      root to: 'money#index', as: 'money'
      post 'withdraw' => 'money#withdraw', as: 'money_withdraw'
    end
    get 'profile' => 'profiles#show'
    root to: 'jobs#index'
  end

以下是控制器操作:

# applications_controller.rb

      def opt_out
        @worker = Worker.find(params[:id])
        if @worker.interview_requested? or @worker.onboarding_requested?
          if @worker.fire_state_event(:opt_out)
            AdminsMailer.sweeper_opted_out(@worker.id)
            redirect_to root_url, notice: "You have successfully opted out of the application process. We're sorry to see you go, and hope you'll consider returning in the future!"
          else
            redirect_to root_url, alert: "There was a problem. Please contact Support if you need further assistance."
          end
        else
          redirect_to root_url, alert: "There was a problem. Please contact Support if you need further assistance."
        end
      end

以下是rake routes

opt_out_worker_application PUT    /worker/application/opt_out(.:format)           worker/application#opt_out
                worker_application POST   /worker/application(.:format)                   worker/applications#create
            new_worker_application GET    /worker/application/new(.:format)               worker/applications#new
                                   GET    /worker/application(.:format)                   worker/applications#show

2 个答案:

答案 0 :(得分:4)

这是因为这是电子邮件上下文中的链接。它是documented behavior

  

方法:HTTP动词的符号 - 此修饰符将动态创建   HTML表单并立即提交表单进行处理   指定了HTTP谓词。用于让链接执行POST操作   在删除记录等危险行为(搜索机器人可以   跟踪,同时抓住你的网站)。支持的动词有:post,:delete,   :补丁,和:放。请注意,如果用户禁用了JavaScript,则   请求将回退到使用GET。如果href:'#'使用和用户   已禁用JavaScript单击该链接将无效。如果你   依赖于POST行为,你应该在你的行为中检查它   控制器的动作是使用请求对象的post?方法,   删除?,补丁?或者放??

有安全理由拒绝电子邮件中的可执行JavaScript以及表单。因此,使用JS呈现表单并执行PUT请求是不可能的,因此这可以回到GET,如上面引用中所述。

答案 1 :(得分:4)

link_to上的方法选项有效,因为您的应用包含一些拦截链接点击的JavaScript。该javascript使用正确的方法创建表单(为浏览器不支持的请求方法添加输入元素)并支持它。

这不会在电子邮件中发挥作用:您的网站的javascript不存在,而电子邮件客户端通常不会运行javascript。

在某些情况下包含实际表单,但经常不会(或显示可怕的警告) - 例如,请参阅this question

没有太多可以选择简单的" get"很遗憾地链接(你当然可以进入一个确认页面,你有一个按钮/链接可以发送一个帖子请求)。