acts_as_importable 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -16,7 +16,15 @@ If model name is not specified, it will use the controller name to find the mode
16
16
 
17
17
  acts_as_importable :product, :scoped => :current_store
18
18
 
19
- This will import all material records within the current_store object returned by the controller#current_store method. Product should have a belongs_to association to Store for this feature to work.
19
+ This will import all products within the current_store object returned by the controller#current_store method. Product should have a belongs_to association to Store for this feature to work.
20
+
21
+ ==== Updating existing objects:
22
+
23
+ acts_as_importable :product, :find_existing_by => :name
24
+
25
+ This will update existing products whose name matches with the value of name column in the csv row. However, if :find_by_existing is not specified, no attempt will be made to lookup existing products. e.g. the following will always create new products
26
+
27
+ acts_as_importable :product
20
28
 
21
29
  === Add the following to your Model:
22
30
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.3.0
1
+ 0.4.0
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{acts_as_importable}
8
- s.version = "0.3.0"
8
+ s.version = "0.4.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Jagdeep Singh"]
12
- s.date = %q{2011-01-13}
12
+ s.date = %q{2011-01-15}
13
13
  s.description = %q{Use this gem to add import/export to .csv functionality to your activerecord models}
14
14
  s.email = %q{jagdeepkh@gmail.com}
15
15
  s.extra_rdoc_files = [
@@ -28,16 +28,14 @@ module ImportExport
28
28
 
29
29
  def import
30
30
  @new_objects = []
31
- filename = "#{UPLOADS_PATH}/#{self.controller_name}.csv"
32
- context = {}
33
- self.class.context.each_pair do |key, value|
34
- context[key] = self.send(value)
35
- end
31
+ filename = upload_file_name
32
+ context = self.class.context.clone
33
+ context[:scoped] = self.send(context[:scoped]) if context[:scoped]
36
34
 
37
35
  if File.exists? filename
38
36
  begin
39
37
  @new_objects = self.class.model_class.import(filename, context)
40
- flash[:notice] = "Import Successful - #{@new_objects.length} New #{self.class.model_class.name.underscore.humanize.pluralize}"
38
+ flash[:notice] = "Import Successful - Imported #{@new_objects.length} #{self.class.model_class.name.underscore.humanize.pluralize}"
41
39
  rescue Exception => e
42
40
  logger.error "Error: Unable to process file. #{e}"
43
41
  flash[:error] = "Error: Unable to process file. #{e}"
@@ -54,8 +52,7 @@ module ImportExport
54
52
  require 'ftools'
55
53
  if params[:csv_file] && File.extname(params[:csv_file].original_filename) == '.csv'
56
54
  File.makedirs "#{UPLOADS_PATH}"
57
- File.open("#{UPLOADS_PATH}/#{self.controller_name}.csv", "wb") { |f| f.write(params[:csv_file].read)}
58
- flash[:notice] = "Successful import of #{self.controller_name} data file"
55
+ File.open(upload_file_name, "wb") { |f| f.write(params[:csv_file].read)}
59
56
  else
60
57
  flash[:error] = "Error! Invalid file, please select a csv file."
61
58
  end
@@ -64,8 +61,12 @@ module ImportExport
64
61
 
65
62
  private
66
63
 
64
+ def upload_file_name
65
+ @upload_file_name ||= "#{UPLOADS_PATH}/#{self.controller_name}_#{request.session_options[:id]}.csv"
66
+ end
67
+
67
68
  def export_file_name
68
- "#{Time.now.to_formatted_s(:number)}_#{self.controller_name}_export.csv"
69
+ @export_file_name ||= "#{Time.now.to_formatted_s(:number)}_#{self.controller_name}_export.csv"
69
70
  end
70
71
 
71
72
  end # end of module InstanceMethods
data/lib/import_export.rb CHANGED
@@ -13,9 +13,8 @@ module ModelMethods
13
13
  self.export_fields = options[:export_fields]
14
14
  send :include, InstanceMethods
15
15
  end
16
-
17
- def import(filename, context)
18
16
 
17
+ def import(filename, context)
19
18
  collection = []
20
19
  headers, *data = self.read_csv(filename)
21
20
  scope_object = context[:scoped]
@@ -26,40 +25,18 @@ module ModelMethods
26
25
 
27
26
  begin
28
27
  class_or_association = scope_object ? scope_object.send(self.table_name) : self
29
- key_field = self.import_fields.first
30
- key_value = data_row[0]
31
- finder_method = "find_by_#{key_field}"
32
- existing_element = class_or_association.send(finder_method, key_value)
33
- element = existing_element || class_or_association.new
28
+ if key_field = context[:find_existing_by]
29
+ key_value = data_row[index_of(key_field)]
30
+ element = class_or_association.send("find_by_#{key_field}", key_value) || class_or_association.new
31
+ else
32
+ element = class_or_association.new
33
+ end
34
34
 
35
35
  Rails.logger.info "#{element.new_record? ? "Creating new" : "Updating existing"} record from #{data_row.inspect}"
36
36
 
37
37
  self.import_fields.each_with_index do |field_name, field_index|
38
38
  if field_name.include?('.')
39
- method_name = 'assign_' + field_name.split('.')[0]
40
- if element.respond_to?(method_name)
41
- element.send method_name, data_row
42
- elsif element.respond_to?("#{field_name.split('.')[0]}_id")
43
- create_record = field_name.include?('!')
44
- split_field = field_name.gsub(/!/,'').split('.').compact
45
- initial_class = split_field[0].classify.constantize
46
- if initial_class and initial_class.respond_to?("find_by_#{split_field[1]}")
47
- begin
48
- e = initial_class.send("find_by_#{split_field[1]}", data_row[field_index])
49
- rescue
50
- e = nil
51
- end
52
- # try to create a new record if not found in database and if '!' is present
53
- if e.nil? and create_record and !data_row[field_index].blank?
54
- e = initial_class.create!("#{split_field[1]}" => data_row[field_index])
55
- end
56
- if e.kind_of?(ActiveRecord::Base)
57
- element["#{split_field[0]}_id"] = e.id
58
- end
59
- else
60
- e = nil
61
- end
62
- end
39
+ assign_association(element, field_name, field_index, scope_object, data_row)
63
40
  else
64
41
  element.send "#{field_name}=", data_row[field_index]
65
42
  end
@@ -130,10 +107,45 @@ module ModelMethods
130
107
  raise ArgumentError, "File does not exist."
131
108
  end
132
109
  end
110
+
111
+ def index_of(fieldname)
112
+ @import_field_indices ||= {}
113
+ @import_field_indices[fieldname] ||= self.import_fields.index{ |f| f.to_s == fieldname.to_s }
114
+ end
115
+
116
+ protected
117
+
118
+ def assign_association(element, field_name, field_index, scope_object, data_row)
119
+ create_record = field_name.include?('!')
120
+ association_name, association_attribute = field_name.gsub(/!/,'').split('.')
121
+ assign_association_method = "assign_#{association_name}"
122
+ association_fk = "#{association_name}_id"
123
+
124
+ if element.respond_to?(assign_association_method)
125
+ element.send assign_association_method, data_row
126
+ elsif element.respond_to?(association_fk)
127
+ association_class = association_name.classify.constantize
128
+
129
+ if scope_object && scope_object.respond_to?(association_class.table_name)
130
+ association_class = scope_object.send(association_class.table_name)
131
+ end
132
+
133
+ finder_method = "find_by_#{association_attribute}"
134
+ if association_class and association_class.respond_to?(finder_method)
135
+ e = association_class.send(finder_method, data_row[field_index])
136
+ if e.nil? and create_record and !data_row[field_index].blank?
137
+ e = association_class.create!(association_attribute => data_row[field_index])
138
+ end
139
+ element[association_fk] = e.id if e
140
+ end
141
+ end
142
+ end
133
143
  end
134
144
 
135
145
  module InstanceMethods
136
- # any method placed here will apply to instaces, like @hickwall
146
+ def index_of(fieldname)
147
+ self.class.index_of(fieldname)
148
+ end
137
149
  end
138
150
 
139
151
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: acts_as_importable
3
3
  version: !ruby/object:Gem::Version
4
- hash: 19
4
+ hash: 15
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
- - 3
8
+ - 4
9
9
  - 0
10
- version: 0.3.0
10
+ version: 0.4.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Jagdeep Singh
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-01-13 00:00:00 +05:30
18
+ date: 2011-01-15 00:00:00 +05:30
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency