How to pass variables from a controller to a model in Rails 5.2?


I created a controller an model to import an Excel sheet, and insert or update records in the database.

It works fine, and I now want to add a counter of inserts / updates to notify the user. I was expecting to do it using instance variables, but this does not work: the variables are not known inside the model.

Can you help me understand why and find a solution?

Here is the controller:

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

Here is the model:

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