ruby-on-rails - 如何将变量从控制器传递到 Rails 5.2 中的模型?
问题描述
我创建了一个控制器模型来导入 Excel 工作表,并在数据库中插入或更新记录。
它工作正常,我现在想添加一个插入/更新计数器来通知用户。我期望使用实例变量来做到这一点,但这不起作用:模型内部不知道变量。
您能帮我理解原因并找到解决方案吗?
这是控制器:
class ClassificationValuesImportsController < ApplicationController
# Check for active session
before_action :authenticate_user!
def new
@classification = Classification.find(params[:classification_id])
@classification_values_import = ClassificationValuesImport.new
end
def create
@update_counter = 0
@insert_counter = 0
@classification = Classification.find(params[:classification_id])
@classification_values_import = ClassificationValuesImport.new(params[:classification_values_import])
if @classification_values_import.file.nil?
render :new, notice: t('FileNameCannotBeEmpty')
end
if @classification_values_import.save
redirect_to @classification, notice: "#{t('ImportedObjects')}: #{@insert_counter} inserted, #{@update_counter} updated"
else
@classification_values_import.errors.full_messages.each do |msg|
puts msg
@classification.errors[:base] << msg
end
render :new
end
end
end
这是模型:
class ClassificationValuesImport
include ActiveModel::Model
extend ActiveModel::Naming
include ActiveModel::Conversion
include ActiveModel::Validations
attr_accessor :file, :parent_id
def initialize(attributes = {})
attributes.each { |name, value| send("#{name}=", value) }
end
def persisted?
false
end
def save
if imported_values_lists.map(&:valid?).all?
imported_values_lists.each(&:save!)
puts "///////////////////// Count of linked values_lists /////////////////////"
print "Updates : "
puts @update_counter
print "Insert : "
puts @insert_counter
true
else
imported_values_lists.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_values_lists
@imported_values_lists ||= load_imported_values_lists
end
def load_imported_values_lists
# Read input file
spreadsheet = self.open_spreadsheet(file)
puts spreadsheet.sheets
puts spreadsheet.sheets[1]
spreadsheet.default_sheet = spreadsheet.sheets.last
header = spreadsheet.row(1)
# Get the list of values lists to upload
@classification = Classification.find(parent_id)
playground_id = @classification.playground_id
values_lists = Array.new
@classification.values_lists_classifications.order(:sort_order).each do |link|
values_lists[link.sort_order] = link.values_list_id
end
header = spreadsheet.row(1)
# Upload or update values for each values list
(2..spreadsheet.last_row).map do |i|
# Read column indexes
code = header.index("Code") +1
parent = header.index("Parent") +1
level = header.index("Level") +1
valid_from = header.index("Valid from") +1
valid_to = header.index("Valid to") +1
name = header.index("Name_en") +1
if record = Value.find_by(values_list_id: values_lists[spreadsheet.cell(i,level).to_i], code: spreadsheet.cell(i,code))
@update_counter += 1
else record = Value.new(playground_id: playground_id, values_list_id: values_lists[spreadsheet.cell(i,level).to_i], code: spreadsheet.cell(i,code))
@insert_counter += 1
end
#record.active_from = spreadsheet.cell(i,'Valid from')
#record.active_to = spreadsheet.cell(i,'Valid to')
record.name = spreadsheet.cell(i,name)
record.description = 'HCL upload test'
record.created_at = record.created_at || Time.now
record.updated_at = record.updated_at || Time.now
#record.anything = { 'Comment' => 'This is a test', 'Author' => 'Fred'}.to_json
### create first translation for current_user if data is available
#record.name_translations.build(field_name: 'name', language: 'en', translation: record.name) unless record.name.blank?
#record.description_translations.build(field_name: 'description', language: language, translation: record.description) unless record.description.blank?
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
解决方案
您可以在模型中定义瞬态属性:
attr_accessor :update_counter, :insert_counter
...他们设置和访问来自控制器和模型的值,作为常规属性:
@classification.update_counter = 0
@classification.insert_counter = 0
但是,您应该小心,因为这种方法会使调试值的来源变得更加困难。
我相信最好的办法是将整个逻辑移动到模型中,处理update_counter
并insert_counter
作为实例变量,然后为它们公开一个公共 getter。在这种情况下,您可以使用attr_reader :update_counter, :insert_counter
而不是。attr_accessor
然后,您可以使用@classification.update_counter
来获取控制器中的值。
如果模型需要来自控制器的任何信息,您可以将它们作为参数传递给save
方法,并根据需要将它们向前传递。
推荐阅读
- javascript - 为什么我的php页面显示错误
我正在尝试创建一个仅使用 PHP 的网页(不需要任何 HTML 元素),但是当我运行该页面时,出现以下错误:
- android - 如何正确测试所选主题是浅色模式还是深色模式
- amazon-web-services - 值 0E-16 出现在 S3 parquet 文件中
- ubuntu - 图书馆本身出现错误扭曲 21.7.0
- sharepoint - 从主机访问 SharePoint 提供程序托管列表数据
- javascript - JavaScript 使用 async/await 确保我在实现之前检索值,但仍然返回“未定义”
- c++ - 似乎默认模板参数中的成员访问错误
- python - 这可以被视为一种编程语言吗?
- python - 无法使用 Newton-Raphson 方法获得第四根
- c# - 为什么当玩家在空中按下空格键跳跃时,再次按下空格键会再次跳得更高?