【问题标题】:First argument in form cannot contain nil or be empty while it should not be nil or empty表单中的第一个参数不能包含 nil 或为空,但它不应为 nil 或空
【发布时间】:2018-10-10 15:15:57
【问题描述】:

我遇到了这个问题,我的控制器的“新”和有时“编辑”操作会抛出:

First argument in form cannot contain nil or be empty

虽然我 100% 确定第一个参数不是 nil 也不是空的。为了磨练这一点,我只会询问“新”操作,因为资源只是设置为Resource.new

permissions/new.haml

= form_for @permission do |f|
  = f.label :name, class: 'form-control-label'
  = f.text_field :name, class: 'form-control'

permissions_controller.rb

class PermissionsController < ApplicationController
  before_action :set_permission, only: [:show, :edit, :update, :destroy]

  def new
    @permission = Permission.new
  end

  def show
    @modules = Modules.all
  end

  def index
    // handling content with api calls instead
  end

  ...
end

我遇到这个问题很久了,但直到现在我才想出在我的开发环境中成功重现它。

我可以通过转到同一控制器的“显示”动作,然后返回“索引”动作,然后转到“新”动作来重现此问题。此时,“新”页面不再起作用,直到我编辑控制器文件或重新启动服务器。

在更改控制器(在末尾添加一个空格)或重新启动服务器后,它突然又可以工作了。

这不是发生这种情况的唯一资源。像用户这样的其他资源通常也有同样的问题。我有多个项目都有相同的问题,但不知何故消失了,所以我从来没有费心对此进行更多调查。

Ruby 版本:2.3.5p376

Rails 版本:5.1.4

编辑:

我注意到如果我注释掉Modules.all,我将无法再复制它。

modules 不是一个 activerecord 类,它是一个帮助类,让我可以读取目录中的不同文件,这样读取会不会有问题?

modules.rb

class Modules
  def self.all
    controllers = Dir.glob("#{Rails.root}/app/controllers/**/*.rb").
      map{ |e|
        if e.include?('/api/')
          e.match(/api\/[^\/]*\/[^\/]*.rb/)[0].gsub('.rb', '').gsub('/', '::_').camelcase
        else
          e.match(/[^\/]*.rb/)[0].gsub('.rb', '').camelcase
        end
      }
    modules = {}
    controllers.each do |e|
      c = Object.const_get e
      modules[e.gsub(':','').gsub('Controller', '').underscore] = get_actions_for c if
        !no_permission_needed_for e and c.action_methods.size > 0
    end

    return modules
  end

  def self.get_actions_for(controller)
    actions = controller.action_methods
    grouped_actions.each do |key, value|
      actions.delete(key)
    end

    return actions
  end

  def self.grouped_actions
    {"new" => "create", "edit" => "update"}
  end

end

编辑:

我注意到我正在尝试调用actions.delete(key),其中操作是Set 的字符串,其中keyString

当我执行actions = controller.action_methods.to_a 并将集合强制设置为数组时,我的问题似乎消失了。至少我不能再复制它了。现在我想知道 ruby​​ 是否存在根本性的问题,即从 Set 中删除某些内容会导致一些奇怪的事情发生。

【问题讨论】:

  • 我想知道您为什么将表单提交给url: permissions_path,即通过向index 方法发送POST/PUT 请求?为什么不使用标准的create / update
  • 你可能指的是permissions_controller.rb,而不是permissionscontroller.rb
  • 我的错,错字,文件被正确命名为 permissions_controller.rb。至于额外的 url,你是对的,它是不必要的,表单助手应该自己正确处理它
  • 我刚想到如果表单验证失败,您可以从index 操作调用渲染new.haml 模板,其中@permission 未设置
  • 即使我在index 中设置了@permission = Permission.new,问题仍然存在。所以我猜这不是原因。

标签: ruby-on-rails ruby ruby-on-rails-5


【解决方案1】:

一种可行但不推荐的方法是在表单中初始化Permission 实例:

<%= form_for Permission.new do |f| %>

检查包含您的表单的视图是否实际上是由您的PermissionsControllernew 操作呈现的。

【讨论】:

  • 我知道它会这样工作,但正如你所说,不推荐这样做,如果无法保存资源,它也不会再次正确填充字段。我也更新了我的问题,我很确定在幕后发生了一些奇怪的事情。
  • PermissionsControllernew动作渲染的表单,你能确认一下吗?
  • 肯定,表单由new 操作呈现。我已经解决了我的问题,但这给我留下了更大的问题,即为什么 Set 以奇怪的方式对框架架构起作用
【解决方案2】:

我想我已经明白了。

我注意到的是,在modules.rb 中,我通过controller.action_methods 在控制器中加载动作。在此之后,我将删除 newedit 操作。

我假设我只是收到一组包含动作名称而不是实际动作的字符串。因此,如果我删除 newedit 操作,我的视图将默认为 ActionController::Base 中的 newedit 操作,这似乎是合乎逻辑的。这意味着未设置 @permission 并且视图会引发当之无愧的错误。

我假设这样做会在控制器的运行时删除这些操作。这意味着它当然会在我重新启动服务器后再次工作。

所以我通过 controller.action_methods.to_a 解决了我的问题,这会强制分离控制器中的实际操作。在此之后,我可以随意删除此数组中不需要的字符串。

故事的寓意:注意controller.action_methods

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多