Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
518 views
in Technique[技术] by (71.8m points)

ruby - Rails 3.2 `link_to` (in email) with `method: :put` still producing GET request

In my app I have automated e-mails reminding applications to complete the next step in the interview process. The e-mail has an opt out link which, when clicked, should hit a controller action that fires a state machine event to change their state to opted_out. The link is not working, and from the localhost console it seems to be because the link is still producing a GET request, for which there is no route (the error is ActionController::RoutingError (Not Found):).

Here is the console displaying the undesired GET request:

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"}

Here is the link:

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'

Here are all the routes for the worker namespace:

# 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

Here is the controller action:

# 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

Here is 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
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

It's because this is a link in context of an email. It's documented behavior:

method: symbol of HTTP verb - This modifier will dynamically create an HTML form and immediately submit the form for processing using the HTTP verb specified. Useful for having links perform a POST operation in dangerous actions like deleting a record (which search bots can follow while spidering your site). Supported verbs are :post, :delete, :patch, and :put. Note that if the user has JavaScript disabled, the request will fall back to using GET. If href: '#' is used and the user has JavaScript disabled clicking the link will have no effect. If you are relying on the POST behavior, you should check for it in your controller's action by using the request object's methods for post?, delete?, patch?, or put?.

There are security reasons to disallow executable JavaScript in emails, as well as forms. Therefore, it's impossible to render a form with JS and execute a PUT request, so this falls back to GET as stated in citation above.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...