mirror of
https://github.com/maybe-finance/maybe.git
synced 2025-08-02 20:15:22 +02:00
Add support for different column separator in csv import logic (#1096)
* add col_sep to import model * add validation for col_sep column * add col_sep option to csv import model * make use of col_sep option in import model * add column separator field to new/edit action of an import * add col_sep parameter to create/update action * fix spacing between fields Co-authored-by: Zach Gollwitzer <zach.gollwitzer@gmail.com> Signed-off-by: Alexander Schrot <alexander@axs-labs.com> --------- Signed-off-by: Alexander Schrot <alexander@axs-labs.com> Co-authored-by: Zach Gollwitzer <zach.gollwitzer@gmail.com>
This commit is contained in:
parent
707c5ca0ca
commit
4527482aa2
11 changed files with 117 additions and 19 deletions
|
@ -18,14 +18,14 @@ class ImportsController < ApplicationController
|
|||
|
||||
def update
|
||||
account = Current.family.accounts.find(params[:import][:account_id])
|
||||
@import.update! account: account, col_sep: params[:import][:col_sep]
|
||||
|
||||
@import.update! account: account
|
||||
redirect_to load_import_path(@import), notice: t(".import_updated")
|
||||
end
|
||||
|
||||
def create
|
||||
account = Current.family.accounts.find(params[:import][:account_id])
|
||||
@import = Import.create!(account: account)
|
||||
@import = Import.create! account: account, col_sep: params[:import][:col_sep]
|
||||
|
||||
redirect_to load_import_path(@import), notice: t(".import_created")
|
||||
end
|
||||
|
|
|
@ -2,6 +2,7 @@ class Import < ApplicationRecord
|
|||
belongs_to :account
|
||||
|
||||
validate :raw_csv_must_be_parsable
|
||||
validates :col_sep, inclusion: { in: Csv::COL_SEP_LIST }
|
||||
|
||||
before_save :initialize_csv, if: :should_initialize_csv?
|
||||
|
||||
|
@ -88,7 +89,7 @@ class Import < ApplicationRecord
|
|||
|
||||
def get_raw_csv
|
||||
return nil if raw_csv_str.nil?
|
||||
Import::Csv.new(raw_csv_str)
|
||||
Import::Csv.new(raw_csv_str, col_sep:)
|
||||
end
|
||||
|
||||
def should_initialize_csv?
|
||||
|
@ -102,7 +103,7 @@ class Import < ApplicationRecord
|
|||
|
||||
# Uses the user-provided raw CSV + mappings to generate a normalized CSV for the import
|
||||
def generate_normalized_csv(csv_str)
|
||||
Import::Csv.create_with_field_mappings(csv_str, expected_fields, column_mappings)
|
||||
Import::Csv.create_with_field_mappings(csv_str, expected_fields, column_mappings, col_sep)
|
||||
end
|
||||
|
||||
def update_csv(row_idx, col_idx, value)
|
||||
|
@ -176,7 +177,7 @@ class Import < ApplicationRecord
|
|||
|
||||
def raw_csv_must_be_parsable
|
||||
begin
|
||||
CSV.parse(raw_csv_str || "")
|
||||
CSV.parse(raw_csv_str || "", col_sep:)
|
||||
rescue CSV::MalformedCSVError
|
||||
# i18n-tasks-use t('activerecord.errors.models.import.attributes.raw_csv_str.invalid_csv_format')
|
||||
errors.add(:raw_csv_str, :invalid_csv_format)
|
||||
|
|
|
@ -1,12 +1,20 @@
|
|||
class Import::Csv
|
||||
def self.parse_csv(csv_str)
|
||||
CSV.parse((csv_str || "").strip, headers: true, converters: [ ->(str) { str&.strip } ])
|
||||
DEFAULT_COL_SEP = ",".freeze
|
||||
COL_SEP_LIST = [ DEFAULT_COL_SEP, ";" ].freeze
|
||||
|
||||
def self.parse_csv(csv_str, col_sep: DEFAULT_COL_SEP)
|
||||
CSV.parse(
|
||||
csv_str&.strip || "",
|
||||
headers: true,
|
||||
col_sep:,
|
||||
converters: [ ->(str) { str&.strip } ]
|
||||
)
|
||||
end
|
||||
|
||||
def self.create_with_field_mappings(raw_csv_str, fields, field_mappings)
|
||||
raw_csv = self.parse_csv(raw_csv_str)
|
||||
def self.create_with_field_mappings(raw_csv_str, fields, field_mappings, col_sep = DEFAULT_COL_SEP)
|
||||
raw_csv = self.parse_csv(raw_csv_str, col_sep:)
|
||||
|
||||
generated_csv_str = CSV.generate headers: fields.map { |f| f.key }, write_headers: true do |csv|
|
||||
generated_csv_str = CSV.generate headers: fields.map { |f| f.key }, write_headers: true, col_sep: do |csv|
|
||||
raw_csv.each do |row|
|
||||
row_values = []
|
||||
|
||||
|
@ -22,18 +30,19 @@ class Import::Csv
|
|||
end
|
||||
end
|
||||
|
||||
new(generated_csv_str)
|
||||
new(generated_csv_str, col_sep:)
|
||||
end
|
||||
|
||||
attr_reader :csv_str
|
||||
attr_reader :csv_str, :col_sep
|
||||
|
||||
def initialize(csv_str, column_validators: nil)
|
||||
def initialize(csv_str, column_validators: nil, col_sep: DEFAULT_COL_SEP)
|
||||
@csv_str = csv_str
|
||||
@col_sep = col_sep
|
||||
@column_validators = column_validators || {}
|
||||
end
|
||||
|
||||
def table
|
||||
@table ||= self.class.parse_csv(csv_str)
|
||||
@table ||= self.class.parse_csv(csv_str, col_sep:)
|
||||
end
|
||||
|
||||
def update_cell(row_idx, col_idx, value)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
<%= styled_form_with model: @import do |form| %>
|
||||
<div class="mb-4">
|
||||
<div class="mb-4 space-y-3">
|
||||
<%= form.collection_select :account_id, Current.family.accounts.alphabetically, :id, :name, { prompt: t(".select_account"), label: t(".account"), required: true } %>
|
||||
<%= form.collection_select :col_sep, Import::Csv::COL_SEP_LIST, :to_s, -> { t(".col_sep_char.#{_1.ord}") }, { prompt: t(".select_col_sep"), label: t(".col_sep"), required: true } %>
|
||||
</div>
|
||||
|
||||
<%= form.submit t(".next"), class: "px-4 py-2 block w-full rounded-lg bg-gray-900 text-white text-sm font-medium cursor-pointer hover:bg-gray-700" %>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue