diff --git a/Gemfile b/Gemfile
index 1669c733e..2f0ef39b7 100644
--- a/Gemfile
+++ b/Gemfile
@@ -67,6 +67,9 @@ gem "strong_migrations", "~> 1.4"
# Use postgresql for data persistence
gem "pg", "~> 1.5"
+# For image manipulation in Active Storage
+gem "image_processing"
+
# Use S3 for file storage
gem "aws-sdk-s3", "~> 1.122", require: false
# Date/Time and Internationalization
diff --git a/Gemfile.lock b/Gemfile.lock
index 2bf84636e..6432ed519 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -163,6 +163,9 @@ GEM
htmlentities (4.3.4)
i18n (1.13.0)
concurrent-ruby (~> 1.0)
+ image_processing (1.12.2)
+ mini_magick (>= 4.9.5, < 5)
+ ruby-vips (>= 2.0.17, < 3)
jaro_winkler (1.5.4)
jbuilder (2.11.5)
actionview (>= 5.0.0)
@@ -206,6 +209,7 @@ GEM
marcel (1.0.2)
matrix (0.4.2)
method_source (1.0.0)
+ mini_magick (4.12.0)
mini_mime (1.1.2)
mini_portile2 (2.8.2)
minitest (5.18.0)
@@ -358,6 +362,8 @@ GEM
ruby-graphviz (1.2.5)
rexml
ruby-progressbar (1.13.0)
+ ruby-vips (2.1.4)
+ ffi (~> 1.12)
sentry-rails (5.9.0)
railties (>= 5.0)
sentry-ruby (~> 5.9.0)
@@ -465,6 +471,7 @@ DEPENDENCIES
faker
friendly_id (~> 5.5.0)
gretel (~> 4.5)
+ image_processing
jbuilder (~> 2.11)
jsbundling-rails
listen (~> 3.8)
diff --git a/app/furniture/marketplace/product.rb b/app/furniture/marketplace/product.rb
index 8499ca8b1..8013197df 100644
--- a/app/furniture/marketplace/product.rb
+++ b/app/furniture/marketplace/product.rb
@@ -2,6 +2,8 @@
class Marketplace
class Product < Record
+ has_one_attached :photo, dependent: :destroy
+
self.table_name = "marketplace_products"
location(parent: :marketplace)
@@ -25,5 +27,15 @@ class Product < Record
attribute :description, :string
monetize :price_cents
+
+ before_commit :standardize_attachment_name
+
+ def standardize_attachment_name
+ return unless photo.attached? && photo.blob.persisted?
+ return if photo.blob.filename.to_s.start_with?(space.id.to_s)
+
+ new_name = "#{space.id}-#{photo.blob.filename}"
+ photo.blob.update(filename: new_name)
+ end
end
end
diff --git a/app/furniture/marketplace/product_component.html.erb b/app/furniture/marketplace/product_component.html.erb
index d3de5bb1e..c70e094b0 100644
--- a/app/furniture/marketplace/product_component.html.erb
+++ b/app/furniture/marketplace/product_component.html.erb
@@ -4,6 +4,11 @@
+ <% if product.photo.present? %>
+
+ <%= image_tag product.photo %>
+
+ <% end %>
<%= description %>
diff --git a/app/furniture/marketplace/product_policy.rb b/app/furniture/marketplace/product_policy.rb
index a6b9ce94b..5448c3255 100644
--- a/app/furniture/marketplace/product_policy.rb
+++ b/app/furniture/marketplace/product_policy.rb
@@ -4,7 +4,7 @@ class Marketplace
class ProductPolicy < Policy
alias_method :product, :object
def permitted_attributes(_params = nil)
- %i[name description price_cents price_currency price] + [tax_rate_ids: []]
+ %i[name description price_cents price_currency price photo] + [tax_rate_ids: []]
end
def update?
diff --git a/app/furniture/marketplace/products/_form.html.erb b/app/furniture/marketplace/products/_form.html.erb
index 8df4c4a4a..7080c1c83 100644
--- a/app/furniture/marketplace/products/_form.html.erb
+++ b/app/furniture/marketplace/products/_form.html.erb
@@ -4,6 +4,7 @@
<%= render "text_area", { attribute: :description, form: f} %>
<%= render "money_field", { attribute: :price, form: f, min: 0, step: 0.01} %>
<%= render "collection_check_boxes", { attribute: :tax_rate_ids, collection: marketplace.tax_rates, value_method: :id, text_method: :label, form: f} %>
+ <%= render "file_field", { attribute: :photo, form: f} %>
<%= f.submit %>
<% end %>
<%- end %>
diff --git a/bin/setup b/bin/setup
index 32d32b67c..a773ea22e 100755
--- a/bin/setup
+++ b/bin/setup
@@ -34,6 +34,9 @@ setup_package "overmind"
setup_package "yarn"
setup_package "redis"
setup_package "graphviz"
+
+setup_package "vips" # for image processing by Active Storage
+
# Firefox web browser is used for interface testing.
brew install --cask firefox
yarn global add maildev
diff --git a/spec/factories/furniture/marketplace.rb b/spec/factories/furniture/marketplace.rb
index e539e1ace..195670b9c 100644
--- a/spec/factories/furniture/marketplace.rb
+++ b/spec/factories/furniture/marketplace.rb
@@ -61,6 +61,10 @@
price_cents { Random.rand(1_00..999_99) }
marketplace
+
+ trait :with_photo do
+ photo { file_fixture_upload("cc-kitten.jpg", "image/jpeg") }
+ end
end
factory :marketplace_cart, class: "Marketplace::Cart" do
diff --git a/spec/fixtures/cc-kitten.jpg b/spec/fixtures/files/cc-kitten.jpg
similarity index 100%
rename from spec/fixtures/cc-kitten.jpg
rename to spec/fixtures/files/cc-kitten.jpg