Rails 5.2中来自表单的InvalidAuthenticityToken

时间:2019-06-23 14:20:21

标签: ruby-on-rails refactoring authenticity-token

我有一个正在运行的Rails5.2应用程序,该应用程序需要数据库重组以改善某些表的组织。自从进行此更改以来,我发现我的某些表单在本地计算机上始终失败,并出现以下错误:

ActionController::InvalidAuthenticityToken in PayBandsController#create

作为重构的一部分,我必须在应用程序中进行很多更改,但是测试都通过了。

我可以通过在相关控制器上(按先前的SO线程)设置skip_before_action :verify_authenticity_token来避免此问题,但这当然不是一个好方法。我想知道根本原因是什么,并消除它。

  • 该表单在其自己的页面上并在HTML中与render一起放置时有效。
  • 当我设置skip_before_action时,该表单有效。
  • 否则该表单将失败,并发送AuthenticityToken错误-即使以前使用相同的结构。

所有这些都在我的本地计算机上以有效会话进行了测试。


该表单是在服务对象内创建的,作为数据表的最后一行(以便我可以在表中添加新行)。这是问题的潜在原因吗?它是在服务对象而不是ERB中呈现的?尽管这种方法在重构之前效果很好...

_table_data += ApplicationController.render(partial: 'datasets/pay_band_numbers_form', locals:{ _dataset_id: _dataset.id, _namespace: _key })

部分内容如下,并且正如我所说,如果单独放置在页面上(例如pay_bands / new),但不需要放置在页面上(在数据集/编辑中),则可以使用:

<%= form_for (PayBand.new), namespace: _namespace do |f| %>
  <%= f.hidden_field :dataset_id, :value => _dataset_id %>
  <%= f.text_field :label, :tabindex => 11, :required => true %>
  <%= f.number_field :number_women, :tabindex => 12, :required => true %>
  <%= f.number_field :number_men, :tabindex => 13, :required => true %>
  <%= f.submit "&#10004;".html_safe, :tabindex => 14, class: "button green-button checkmark" %>
<% end %>

涉及的模型是数据集和PayBand,其定义如下。

class Dataset < ApplicationRecord
  belongs_to :organisation
  has_many :pay_bands, inverse_of: :dataset, dependent: :destroy
  accepts_nested_attributes_for :pay_bands
  default_scope -> { order(created_at: :desc) }
  validates :name, presence: true
  validates :organisation_id, presence: true
end
class PayBand < ApplicationRecord
  belongs_to :dataset
  has_many :ages_salaries_genders, inverse_of: :pay_band, dependent: :destroy
  validates :dataset_id, presence: true
  validates :label, presence: true
end

数据集控制器的相关部分是:

class DatasetsController < ApplicationController
  protect_from_forgery with: :exception
  load_and_authorize_resource
  before_action :authenticate_user!
.
.
.
  def edit
    @dataset = Dataset.find(params[:id])
  end

  def update
    @dataset = Dataset.find(params[:id])
    if @dataset.update_attributes(dataset_params) && dataset_params[:name]
      flash[:notice] = "Survey updated"
      redirect_back fallback_location: dataset_path(@dataset)
    else
      flash[:alert] = "Attempted update failed"
      redirect_to edit_dataset_path(@dataset)
    end
  end
.
.
.
  private

    def dataset_params
      params.require(:dataset).permit(:name)
    end

end

付费范围控制者为:

class PayBandsController < ApplicationController
  protect_from_forgery with: :exception
  # skip_before_action :verify_authenticity_token #DANGEROUS!!!!!
  load_and_authorize_resource
  before_action :authenticate_user!

  def create
    @pay_band = PayBand.new(pay_band_params)
    if @pay_band.save
      flash[:notice] = "Data saved!"
      redirect_to edit_dataset_path(Dataset.find(@pay_band.dataset_id))
    else
      flash[:alert] = "There was an error. Your data was not saved."
      redirect_back fallback_location: edit_dataset_path(Dataset.find(pay_band_params[:dataset_id]))
    end
  end

  private

    def pay_band_params
      params.require(:pay_band).permit(:label, :number_women, :number_men, :avg_salary_women, :avg_salary_men, :dataset_id)
    end
end

在我摆弄数据模型之前,上述所有控制器结构都与应用程序的工作版本相同!

===

修改

经过更多研究,我决定检查标头,所以看看是否可以看到令牌值。但是,meta csrf-token标头标记中的令牌值与此页面上3种不同形式的3种不同令牌中的任一个都不匹配。但是无论如何,一种方法仍然有效(在ERB模板中仅render所用的简单形式),而另两种方法却没有(在服务对象中render中所使用的简单形式)。一切都让我像以前一样困惑!

此外,我尝试从GemFile和application.js文件中删除Turbolink,重新运行bundlerails s,但这没什么区别。

1 个答案:

答案 0 :(得分:0)

为了将来对其他有相同问题(在帮助程序或服务对象中构建的表单的AuthenticityToken错误)进行引用,我将表单直接移到视图中并render将其移至视图中-问题消失了。我已经删除了skip_before_action :verify_authenticity_token,现在一切正常!