act_as_importable 0.0.3 → 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/act_as_importable/base.rb +67 -65
- data/lib/act_as_importable/version.rb +1 -1
- metadata +1 -1
@@ -1,88 +1,90 @@
|
|
1
1
|
require 'active_support'
|
2
2
|
require 'csv'
|
3
3
|
|
4
|
-
module ActAsImportable
|
5
|
-
|
4
|
+
module ActAsImportable
|
5
|
+
module Base
|
6
|
+
extend ActiveSupport::Concern
|
6
7
|
|
7
|
-
|
8
|
+
module ClassMethods
|
8
9
|
|
9
|
-
|
10
|
-
|
11
|
-
|
10
|
+
def import_csv_file(file, options = {})
|
11
|
+
import_csv_text(File.read(file), options)
|
12
|
+
end
|
12
13
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
14
|
+
def import_csv_text(text, options = {})
|
15
|
+
csv = ::CSV.parse(text, :headers => true)
|
16
|
+
results = csv.map do |row|
|
17
|
+
row = row.to_hash.with_indifferent_access
|
18
|
+
import_record(row, options)
|
19
|
+
end
|
18
20
|
end
|
19
|
-
end
|
20
21
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
22
|
+
# Creates or updates a model record
|
23
|
+
# Existing records are found by the column(s) specified by the :uid option (default 'id').
|
24
|
+
# If the values for the uid columns are not provided the row will be ignored.
|
25
|
+
# If uid is set to nil it will import the row data as a new record.
|
26
|
+
def import_record(row, options = {})
|
27
|
+
options = options.reverse_merge!(@default_import_options)
|
28
|
+
row = filter_columns(row, options)
|
29
|
+
record = find_or_create_by(uid_values(row, options))
|
30
|
+
remove_uid_values_from_row(row, options)
|
31
|
+
update_record(record, row)
|
32
|
+
end
|
32
33
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
34
|
+
def update_record(record, row)
|
35
|
+
update_associations(record, row)
|
36
|
+
record.update_attributes(row)
|
37
|
+
record.save!
|
38
|
+
end
|
38
39
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
40
|
+
def filter_columns(row, options = {})
|
41
|
+
row = row.reject { |key, value| Array(options[:except]).include? key } if options[:except]
|
42
|
+
row = row.select { |key, value| Array(options[:only]).include? key } if options[:only]
|
43
|
+
row
|
44
|
+
end
|
44
45
|
|
45
|
-
|
46
|
-
|
47
|
-
|
46
|
+
def uid_values(row, options)
|
47
|
+
Hash[Array(options[:uid]).map { |k| [k, row[k.to_sym]] }]
|
48
|
+
end
|
48
49
|
|
49
|
-
|
50
|
-
|
51
|
-
|
50
|
+
def remove_uid_values_from_row(row, options = {})
|
51
|
+
Array(options[:uid]).each do |field|
|
52
|
+
row.delete(field)
|
53
|
+
end
|
52
54
|
end
|
53
|
-
end
|
54
55
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
56
|
+
def update_associations(record, row)
|
57
|
+
row.each_key do |key|
|
58
|
+
key = key.to_s
|
59
|
+
if key.include?('.')
|
60
|
+
update_association(record, key, row[key])
|
61
|
+
row.delete(key)
|
62
|
+
end
|
61
63
|
end
|
62
64
|
end
|
63
|
-
end
|
64
65
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
66
|
+
def update_association(record, key, value)
|
67
|
+
association_name = key.split('.').first
|
68
|
+
uid_field = key.split('.').last
|
69
|
+
value = find_association_value_with_attribute(association_name, uid_field => value)
|
70
|
+
record.send("#{association_name}=", value) if value
|
71
|
+
end
|
71
72
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
73
|
+
def find_association_value_with_attribute(name, attribute)
|
74
|
+
association = self.reflect_on_association(name.to_sym)
|
75
|
+
association.klass.where(attribute).first
|
76
|
+
end
|
76
77
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
78
|
+
# Note: This will be available by default in rails 4
|
79
|
+
def find_or_create_by(attributes, &block)
|
80
|
+
find_by(attributes) || create(attributes, &block)
|
81
|
+
end
|
81
82
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
83
|
+
# Note: This will by provided by default in rails 4
|
84
|
+
def find_by(attributes)
|
85
|
+
where(attributes).first
|
86
|
+
end
|
86
87
|
|
88
|
+
end
|
87
89
|
end
|
88
90
|
end
|