From e1df6a6f9c82ebcfaba73f2ae52e6b315314f05f Mon Sep 17 00:00:00 2001 From: noelledusahel Date: Thu, 17 Oct 2019 21:15:54 -0400 Subject: [PATCH] Separate out media and row decorators --- .../file_import/place_row_decorator.rb | 47 ++++++++++++++++ app/decorators/place_photo_decorator.rb | 21 +++++++ app/models/place.rb | 14 ++--- spec/fixtures/files/place_without_media.csv | 2 + spec/models/place_spec.rb | 56 ++++++++++++++++--- 5 files changed, 121 insertions(+), 19 deletions(-) create mode 100644 app/decorators/file_import/place_row_decorator.rb create mode 100644 app/decorators/place_photo_decorator.rb create mode 100644 spec/fixtures/files/place_without_media.csv diff --git a/app/decorators/file_import/place_row_decorator.rb b/app/decorators/file_import/place_row_decorator.rb new file mode 100644 index 000000000..1867eb1a7 --- /dev/null +++ b/app/decorators/file_import/place_row_decorator.rb @@ -0,0 +1,47 @@ +class FileImport::PlaceRowDecorator + METHODS_EXCEPT = [:media, :to_h] + def initialize(row) + @row = row.map { |_, value| value.to_s } + end + + def name + at(0) + end + + def type_of_place + at(1) + end + + def description + at(2) + end + + def region + at(3) + end + + def long + at(4) + end + + def lat + at(5) + end + + def media + ::PlacePhotoDecorator.new(at(6).strip) + end + + def to_h + (public_methods(false) - METHODS_EXCEPT).inject({}) do |accumulator, method_name| + accumulator[method_name] = public_send(method_name) + accumulator + end + end + + private + + def at(index) + @row[index] + end +end diff --git a/app/decorators/place_photo_decorator.rb b/app/decorators/place_photo_decorator.rb new file mode 100644 index 000000000..170e94c3b --- /dev/null +++ b/app/decorators/place_photo_decorator.rb @@ -0,0 +1,21 @@ +class PlacePhotoDecorator + def initialize(filename) + @filename = filename + end + + def attachable? + File.exist?(path) + end + + def blob_data + if attachable? + {io: File.open(path), filename: @filename} + end + end + + private + + def path + Rails.root.join(::Place::MEDIA_PATH, @filename) + end +end diff --git a/app/models/place.rb b/app/models/place.rb index bb5bad0fa..127d8cce0 100644 --- a/app/models/place.rb +++ b/app/models/place.rb @@ -11,16 +11,10 @@ class Place < ApplicationRecord def self.import_csv(filename) CSV.parse(filename, headers: true) do |row| - place = Place.find_or_create_by(name: row[0]) - place.lat = row[5].to_f - place.long = row[4].to_f - place.type_of_place = row[1] - place.description = row[2] - place.region = row[3] - if row[6] && File.exist?(Rails.root.join('media', row[6])) - file = File.open(Rails.root.join('media',row[6])) - place.photo.attach(io: file, filename: row[6]) - end + decorator = FileImport::PlaceRowDecorator.new(row) + place = Place.find_or_create_by(decorator.to_h) + place.photo.attach(decorator.media.blob_data) if decorator.media.attachable? + place.save end end diff --git a/spec/fixtures/files/place_without_media.csv b/spec/fixtures/files/place_without_media.csv new file mode 100644 index 000000000..79a3277d4 --- /dev/null +++ b/spec/fixtures/files/place_without_media.csv @@ -0,0 +1,2 @@ +name,type_of_place,description,region,long,lat,media +Iacitata,Community Center,"Iacitata is a restaurant and cultural space that hosts education around indigenous food and farming.",brazil,-48.502270,-1.454980,amazon.jpg \ No newline at end of file diff --git a/spec/models/place_spec.rb b/spec/models/place_spec.rb index 8b6664dac..1601b6d60 100644 --- a/spec/models/place_spec.rb +++ b/spec/models/place_spec.rb @@ -1,6 +1,4 @@ require 'rails_helper' -require 'csv' - RSpec.describe Place, type: :model do describe 'associations' do @@ -9,11 +7,11 @@ end describe 'import_csv' do - it 'is tested against fixture file' do + it 'is tested against fixture file' do expect(file_fixture('place_with_media.csv').read).not_to be_empty end - it 'imports csv' do + it 'imports csv with media' do fixture_data = file_fixture('place_with_media.csv').read described_class.import_csv(fixture_data) @@ -26,24 +24,64 @@ expect(place.region).to eq csv[3] expect(place.long).to eq csv[4].to_f expect(place.lat).to eq csv[5].to_f + expect(place.photo.filename.to_s).to eq csv[6] end - it 'attaches photo' do + it 'does not fail when media is not present' do + fixture_data = file_fixture('place_without_media.csv').read + described_class.import_csv(fixture_data) + place = described_class.first + csv = CSV.parse(fixture_data, headers: true).first + expect(csv[6]).not_to be_nil end - end describe '#photo_format' do - it 'should have a prefix' do + context 'when the attachment is not located in an image folder' do + it 'should add an error' do + fixture_data = file_fixture('place_with_media.csv').read + described_class.import_csv(fixture_data) + place = described_class.first + place.photo.blob.content_type = "file/png" + place.photo_format + + expect(place.photo.blob.content_type.start_with?('image/')).to be(false) + expect(place.errors.count).to eq(1) + end + end + + context 'when the attachment is located in an image folder' do + it 'should not add an error' do + fixture_data = file_fixture('place_with_media.csv').read + described_class.import_csv(fixture_data) + place = described_class.first + place.photo_format + + expect(place.photo.blob.content_type.start_with?('image/')).to be(true) + expect(place.errors.count).to eq(0) + end end end describe 'photo_url' do + it 'should return a url path' do + fixture_data = file_fixture('place_with_media.csv').read + described_class.import_csv(fixture_data) + place = described_class.first + file_name = place.photo.filename.to_s + + expect(place.photo_url).to be_truthy + expect(place.photo_url.include?(file_name)).to be(true) + end end describe 'point_geojson' do + it 'should return a geoJson point' do + fixture_data = file_fixture('place_with_media.csv').read + described_class.import_csv(fixture_data) + place = described_class.first + expect(place.point_geojson.keys).to include('properties') + end end - - pending "add some examples to (or delete) #{__FILE__}" end