0

我正在从事的项目是在 Rails 上使用 haml 标记来开发的。有一个简单形式的视图,如下所示:

= simple_form_for @message, url: [:admin, @request, @message], html: { class: 'form vertical-form} do |f|
  = f.input :text, as: :text, input_html: { class: 'form-control', rows: 5 }
  %br
  = f.input :link_url, input_html: { class: 'form-control'} 
  %br
  - if @message.has_picture_image?
    = f.label :image
    =link_to @message.picture_image, target: "_blank" do
    = image_tag @message.picture_image(:thumb)
    = f.file_field :image, class:'imagen-button'
    = f.input_field :remove_picture, as: :boolean, inline_label: 'Remove'
  %br 
  .form-actions
    = f.submit(t('accept'), class: 'btn btn-large btn-primary')
    = link_to(t('cancel'), [:admin, @message.request, @message], class: 'btn btn-large btn-danger')

在消息模型中有以下方法:

def remove_picture
  self.picture.destroy
end

input_field用于检查是否要删除消息图像(如果存在)。我知道这input_filed让我可以选择检查它,以便当我单击accept按钮时,它会调用消息模型中的 remove_picture 方法。但是,在浏览器部署表单之前,它会出现下一个错误:

undefined method `to_i' for #<Picture:0x007f7675162b58>

Extracted source (around line #39):

37:      = image_tag @message.picture_image(:thumb)
38:    = f.file_field :image, class:'imagen-button'
39:    = f.input_field :remove_picture, as: :boolean, inline_label: 'Remove'
40:  %br
41:  .form-actions
42:    = f.submit(t('accept'), class: 'btn btn-large btn-primary')

如果我重新加载页面,这次将部署表单。我想这是因为第一次,因为图片存在,然后立即remove_picture调用并删除图片,当我重新加载表单时,由于图片已经不存在,所以显示了表单。

显然,我错误地理解了 input_field 的用法。

4

1 回答 1

1

SimpleFormsinput_field是一个将输入绑定到模型属性的助手。当勾选框时,它不会创建一个调用您的方法的框!但它会remove_picture在呈现表单时调用您的方法。

在某些情况下,例如复选框,您需要将输入绑定到未保存在数据库中的属性。我们称这些虚拟属性。它们就像任何旧的 Ruby 属性一样:

class Message < ActiveRecord::Base
  attr_accessor :remove_picture

  # since this method is destructive it should have a bang (!)
  def remove_picture!
    self.picture.destroy
  end
end

你可以像这样使用它:

class MessagesController < ApplicationController
  def update
    @message.update(update_params)
    @message.remove_picture! if message.remove_picture
    # ...
  end

  def update_params
    params.require(:message).allow(:remove_picture)
  end
end

但是有一个更好的方法:

class Message < ActiveRecord::Base
  has_one :picture_image
  accepts_nested_attributes_for :picture_image, allow_destroy: true
end

accepts_nested_attributes_for让我们使用以下方法创建图像picture_image_attributes并销毁图像:

@picture.update(picture_image_attributes: { _destroy: true })

这就是我们设置表单的方式:

= simple_form_for @message, url: [:admin, @request, @message], html: { class: 'form vertical-form} do |f|
  = f.input :text, as: :text, input_html: { class: 'form-control', rows: 5 }
  %br
  = f.input :link_url, input_html: { class: 'form-control'} 
  %br
  - if @message.has_picture_image?
    f.simple_fields_for :picture_image do |pif|
      = pif.label :image
      = link_to @message.picture_image, target: "_blank" do
      = image_tag @message.picture_image(:thumb)
      = pif.file_field :image, class:'imagen-button'
      = pif.input_field :_destroy, as: :boolean, inline_label: 'Remove'
  %br 
  .form-actions
    = f.submit(t('accept'), class: 'btn btn-large btn-primary')
    = link_to(t('cancel'), [:admin, @message.request, @message], class: 'btn btn-large btn-danger')

以及您的强参数白名单:

def update_attributes
  params.require(:message).allow(
    :text, 
    :link_url, 
    picture_image_attributes: [:image, :_destroy]
  )
end 
于 2015-08-05T22:37:14.837 回答