如何将模型验证错误转发到基于 Rails 中另一个模型的视图?

How to forward model validation errors to a view based on another model in Rails?

我创建了一个数据导入页面来集中功能,并删除了许多导入控制器。

我有一个 DataImport 对象来获取 DataImports 控制器的参数。 控制器识别所需的导入模型,并启动导入脚本。如果成功,则呈现导入的对象索引,如果不成功,则返回数据导入表单。

如您所见,在验证失败的情况下,organisation_import.rb 模型中的 save 方法 returns 错误消息列表。如何将此错误列表传递给 @data_import 实例,以便在返回 new 视图时列出错误?

感谢您的帮助!

型号:data_import.rb

class DataImport
  include ActiveModel::Model
  extend ActiveModel::Naming
  include ActiveModel::Conversion
  include ActiveModel::Validations

  attr_accessor  :file, :playground_id, :object_type_id

  def initialize(attributes = {})
    attributes.each { |name, value| send("#{name}=", value) }
  end

  def persisted?
    false
  end

end

查看:new.html.erb

<% provide(:title, (t('DataImport'))) %>

<% provide :page_heading do %>
    <%= t('DataImport') %>
<% end %>

  <%= render partial: "shared/error_list", locals: { errors: @data_import.errors } %>

<div class="row mat-form-row">
  <div class="col-md-12"> <h3><%= t('DataImport') %></h3>
  </div>
</div>

<%= form_for @data_import, html: {id: "input_form"}  do |f| %>

  <div class="row mat-form-row">
    <div class="mat-form-field col-md-3">
      <%= f.label :object_type, t('ObjectType'), class: "mat-form-field-label" %>
      <%= f.collection_select :object_type_id, qdm_object_types('import'), :id, :name, {}, { class: "mat-input-element" } %>
    </div>
  </div>

  <div class="row mat-form-row">
    <div class="mat-form-field col-md-3">
      <%= f.label :file, t('SourceFile'), class: "mat-form-field-label" %>
      <%= f.file_field :file, class: "mat-input-element" %>
    </div>
  </div>
  <br/>

  <div class="row">
    <div class="mat-form-field col-md-3">
      <%= f.label :playground, t('Playground'),  class: "mat-form-field-label" %>
      <%= f.collection_select :playground_id, list_of_playgrounds, :id, :translation, {}, { class: "mat-input-element" } %>
    </div>
  </div>

  <div class="mat-button-group">
    <%= link_to t('Cancel'), root_path, method: :get, class: "mat-stroked-button mat-button-base"  %>
    <%= submit_tag(t('Submit'), :onclick => "submitform();", class: "mat-flat-button mat-button-base mat-primary" ) %>
  </div>
<% end %>

控制器:data_imports_controller.rb

class DataImportsController < ApplicationController
  # Check for active session
  before_action :authenticate_user!

  def new
    @data_import = DataImport.new
  end

  def create
    @data_import = DataImport.new(params[:data_import])
    if @data_import.file.nil?
      render :new, notice: t('FileNameCannotBeEmpty')
    end
    objects = Parameter.find(@data_import.object_type_id).name.downcase.pluralize
    objects_import = "#{objects}Import".classify.constantize
    @imported = objects_import.new(file: @data_import.file, playground: @data_import.playground_id)

    if @imported.save
      redirect_to "/#{objects}", notice: t('ImportedObjects')
    else
      render :new
    end
  end

end

organisations_import.rb型号示例:

class OrganisationsImport
  include ActiveModel::Model
  extend ActiveModel::Naming
  include ActiveModel::Conversion
  include ActiveModel::Validations

  attr_accessor :file, :playground

  def initialize(attributes = {})
    attributes.each { |name, value| send("#{name}=", value) }
  end

  def persisted?
    false
  end

  def save
    if imported_organisations.map(&:valid?).all?
      imported_organisations.each(&:save!)
      true
    else
      imported_organisations.each_with_index do |column, index|
        column.errors.full_messages.each do |message|
          errors.add :base, "Row #{index+2}: #{message}"
        end
      end
      false
    end
  end

  def imported_organisations
    @imported_organisations ||= load_imported_organisations
  end

  def load_imported_organisations
    spreadsheet = self.open_spreadsheet(file)
    spreadsheet.default_sheet = 'Organisations'
    header = spreadsheet.row(1)
    (2..spreadsheet.last_row).map do |i|
      record = Organisation.new
      record.playground_id = $Unicity ? 0 : playground # If only one tenant, then the organisations belong to Governance
      record.code = spreadsheet.cell(i,1).to_s
      record.name = spreadsheet.cell(i,6)
      record.parent_code = spreadsheet.cell(i,2).to_s # before_save action sets the parent_id
      record.organisation_level = spreadsheet.cell(i,3) # overwriten by the before_save action
      record.created_by = 'admin'
      record.updated_by = 'admin'
      record.owner_id = 1 # Administrator
      record.status_id = Parameter.find_by_name("New").id if Parameter.exists?(:name => ("New"))

      # Add description translations
      next_cell = 6
      ApplicationController.helpers.list_of_languages.order(:property).each do |translation|
        record.description_translations.build(field_name: 'name', language: translation.property, translation: spreadsheet.cell(i,next_cell))
        next_cell += 1
        record.description_translations.build(field_name: 'description', language: translation.property, translation: spreadsheet.cell(i,next_cell))
        next_cell += 1
      end
      puts "####################### test ####################################"
      puts record.attributes

      record
    end
  end

  def open_spreadsheet(file)
    case File.extname(file.original_filename)
    when ".csv" then Roo::CSV.new(file.path, csv_options: {col_sep: ";"})
#    when ".xls" then Roo::Excel.new(file.path, nil, :ignore)
    when ".xlsx" then Roo::Excelx.new(file.path)
    else raise "Unknown file type: #{file.original_filename}"
    end
  end
end

您可以将错误消息附加到 @data_import 对象的错误中。

@imported.errors.full_messages.each{|msg| @data_import.errors[:base] << msg}