【问题标题】:How to declare objects for nested form in rails 4如何在rails 4中为嵌套形式声明对象
【发布时间】:2015-04-29 16:14:39
【问题描述】:

我正在接近使用 Rails 的第二周,并且我的应用程序的结构几乎已经完成(我认为/希望)。我正在为一个慈善机构建立一个员工网站,作为他们工作的一部分,该网站收集并擦除计算机(在将它们送到非洲学校之前!)。

我已将我的应用设置为包含人员、计算机和擦除模型/类,并将擦除详细信息的表单嵌套在计算机详细信息的表单中。当我创建一台新计算机时,我可以毫无问题地输入擦除详细信息,如果我编辑现有计算机的擦除详细信息已经有擦除详细信息,它也可以很好地工作。但是,当我将擦除详细信息添加到现有计算机不擦除详细信息时,我收到以下错误:

undefined method `staff=' for nil:NilClass
Extracted source (around line #49):

如何正确地将 computer.wipe.staff = 设置为当前用户。请注意,要编辑或提交擦除详细信息,用户必须登录。

我的模型如下(忽略不相关的验证等):

class Staff < ActiveRecord::Base
  has_many :wipes
  before_save { self.staff_email = staff_email.downcase }
  validates :staff_name, presence: true, length: { minimum: 5, maximum: 50}
  has_secure_password
end

class Computer < ActiveRecord::Base
  has_one :wipe, dependent: :destroy
  accepts_nested_attributes_for :wipe
end

class Wipe < ActiveRecord::Base
  belongs_to :computer#, dependent: destroy
  belongs_to :staff
  validates :staff_id, presence: true
 #validates :computer_id, presence: true
  validates :action_taken, presence: true, length: { minimum: 2, maximum: 250 }
end

我的电脑控制器如下:

class ComputersController < ApplicationController
  before_action :set_computer, only: [:edit, :update, :show]
  before_action :require_user, except: [:new, :create]

  layout :new_layout, only: [:new, :update]

  def new
    @computer = Computer.new
    @computer.build_wipe
  end

  def create
    @computer = Computer.new(computer_params)
    if logged_in?
      @computer.wipe.staff = current_user
    end
    if @computer.save
      flash[:success] = "You're computer's details have been submitted successfully!"
      redirect_to computers_path
    else
      render :new, layout: new_layout
    end
  end

  def edit
    unless @computer.wipe
      @computer.build_wipe
    end
  end

  def update
    @computer.wipe.staff = current_user #This is the line not working, yet seems to work correctly in the create action
    if @computer.update(computer_params)
      flash[:success] = "The computer's details have been updated successfully!"
      redirect_to computer_path(@computer)
    else
      render :edit
    end
  end

  private

    #Whitelisting variables
    def computer_params
      params.require(:computer).permit(:manufacturer, :computer_type, :specification, :donor, :model_no, :serial_no, :product_key, :turingtrack, :picture, wipe_attributes: [:id, :action_taken, :staff_id])
    end

    def set_computer
      @computer = Computer.find(params[:id])
    end

end

我的看法是:

<div class="row">
  <div class="well col-md-8 col-md-offset-2">
    <%= form_for(@computer, html: { multipart: true }) do |f| %>

      <%= f.label :manufacturer %>
      <%= f.text_field :manufacturer, :placeholder => "Toshiba" %>
      <%= f.label :computer_type, "Computer Type" %>
      <%= f.text_field :computer_type, :placeholder => "Laptop"%>

      <% if logged_in? %>
        <br><strong>Wiping Details:<br><br></strong>
        <%= f.fields_for :wipe do |wipe_form| %>
          <%= wipe_form.label :action_taken %>
          <%= wipe_form.text_field :action_taken %>
        <% end %>
      <% end %>

      <%= f.submit(@computer.new_record? ? "Submit Details" : "Submit Edited Details", class: "btn btn-success") %>
    <% end %>

  </div>
</div>

此外,目前我在计算机表单内使用嵌套擦除表单时没有设置computer_id,它似乎会自动分配它(例如,如果我创建了一台新计算机/编辑一台并输入擦除详细信息,@该擦除的 987654326@ 是也创建/编辑的计算机的擦除)。这个假设正确吗?我在某处读到无法验证父母的外键,但它太简短而无法真正理解。当我尝试在擦拭模型中验证 computer_id 时会引发错误,因此验证被注释掉。为什么会这样,这样下去可以吗?

谢谢大家

【问题讨论】:

  • 您的@computer.wipe 未设置。即它是nil

标签: ruby-on-rails ruby-on-rails-4 nested-forms has-one


【解决方案1】:

根据错误:

    undefined method `staff=' for nil:NilClass.

这表明 @computer.wipe 为 nil。因此,虽然您的 set_computer 方法可以根据提供的 id 正确找到计算机,但 @computer 没有关联的 wipe

编辑:这可能与您的 build_wipe 方法中的问题有关,该方法未正确设置擦除。

【讨论】:

  • 嘿@Andrew,感谢您的建议。我意识到我的@computer.wipenil,但我似乎不知道为什么。根据 API 文档,build_wipe 应该用于 has_one 关系,例如我的关系,而不是 wipe.build 用于 has_many。此外,相同的代码似乎成功地为创建操作生成了一个实例。如果没有build_wipe,我的表单甚至不会生成输入任何内容的框。关于我下一步调试的任何想法?谢谢
  • 我没有遇到过 build_wipe 方法。为什么不给@computer 分配一个Wipe 对象呢?例如@computer.wipe = Wipe.new
  • 在我的编辑操作中设置@computer.wipe = Wipe.new 时,在加载编辑视图时出现以下错误:ActiveRecord::RecordNotSaved in ComputersController#edit, Failed to save the new associated wipe.
【解决方案2】:

我似乎已经解决了我的问题,但我不太明白它为什么会起作用。 我在编辑和更新操作中都构建了一个擦除对象。第一个在表单中创建输入字段,第二个是分配工作人员时使用的实例。请注意,当我在控制台中检查是否已创建两个擦除对象时,根据需要,只有一个对象具有。

def edit
  unless @computer.wipe
    @computer.build_wipe
  end
end

def update
  if @computer.wipe 
  else
    @computer.build_wipe
  end
  @computer.wipe.staff = current_user
  if @computer.update(computer_params)
    flash[:success] = "The computer's details have been updated successfully!"
    redirect_to computer_path(@computer)
  else
    render :edit
  end
end

【讨论】:

    猜你喜欢
    • 2013-07-20
    • 2010-10-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-30
    相关资源
    最近更新 更多