如何将模型验证错误转发到基于 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}
我创建了一个数据导入页面来集中功能,并删除了许多导入控制器。
我有一个 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}