Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Store metadata for solidus resources #5951

Open
wants to merge 15 commits into
base: main
Choose a base branch
from

Conversation

shahmayur001
Copy link

@shahmayur001 shahmayur001 commented Nov 27, 2024

Summary

This implementation extends the Solidus framework to add metadata support across multiple Spree resources. It involves database migrations, model enhancements, attribute updates, API configuration, and comprehensive testing to ensure robust functionality.

List of Resources
The following Spree resources are configured to support metadata fields:

  • spree_orders
  • spree_line_items
  • spree_shipments
  • spree_payments
  • spree_stock_movements
  • spree_addresses
  • spree_refunds
  • spree_products
  • spree_customer_returns
  • spree_stock_locations
  • spree_store_credit_events
  • spree_stores
  • spree_taxonomies
  • spree_taxons
  • spree_variants
  • spree_users
  • spree_return_authorizations

Database Schema Updates

To support metadata, two new JSON/JSONB columns (public_metadata and private_metadata) are added to each of the above resources.

Migration

class AddPublicAndPrivateMetadataToSpreeResources < ActiveRecord::Migration[7.0]
  def change
    %i[
      spree_orders
      spree_line_items
      spree_shipments
      spree_payments
      spree_stock_movements
      spree_addresses
      spree_refunds
      spree_products
      spree_customer_returns
      spree_stock_locations
      spree_store_credit_events
      spree_stores
      spree_taxonomies
      spree_taxons
      spree_variants
      spree_users
      spree_return_authorizations
    ].each do |table_name|
      change_table table_name do |t|
        if t.respond_to?(:jsonb)
          add_column table_name, :public_metadata, :jsonb, default: {}
          add_column table_name, :private_metadata, :jsonb, default: {}
        else
          add_column table_name, :public_metadata, :json, default: {}
          add_column table_name, :private_metadata, :json, default: {}
        end
      end
    end
  end
end

PR Model Configuration
A shared concern Spree::Metadata is introduced to handle serialization and facilitate operations on the metadata fields.

Concern Implementation

module Spree
  module Metadata
	extend ActiveSupport::Concern

	included do
  	  store :public_metadata, coder: JSON
  	  store :private_metadata, coder: JSON
	end
  end
end

Attribute Configuration

The public_metadata and private_metadata fields are incorporated into the Spree attribute system.

Permitted Attributes

@@metadata_attributes = [private_metadata: {}, public_metadata: {}]

ATTRIBUTES = [
  :address_attributes,
  :address_book_attributes,
  :checkout_address_attributes,
  :checkout_delivery_attributes,
  :checkout_payment_attributes,
  :checkout_confirm_attributes,
  :credit_card_update_attributes,
  :customer_return_attributes,
  :image_attributes,
  :inventory_unit_attributes,
  :line_item_attributes,
  :option_type_attributes,
  :option_value_attributes,
  :payment_attributes,
  :product_attributes,
  :product_properties_attributes,
  :property_attributes,
  :return_authorization_attributes,
  :shipment_attributes,
  :source_attributes,
  :stock_item_attributes,
  :stock_location_attributes,
  :stock_movement_attributes,
  :store_attributes,
  :taxon_attributes,
  :taxonomy_attributes,
  :user_attributes,
  :variant_attributes,
  :metadata_attributes
]

Strong Parameters

def permitted_product_attributes
  permitted_attributes.product_attributes + metadata_attributes + [
	product_properties_attributes: permitted_product_properties_attributes
  ]
end

API Configuration

preference :product_attributes, :array, default: [
  :id, :name, :description, :available_on,
  :slug, :meta_description, :meta_keywords, :shipping_category_id,
  :taxon_ids, :total_on_hand, :meta_title,
  :private_metadata, :public_metadata
]

Testing

Add unit tests to verify the functionality of metadata fields.
RSpec Example

describe "metadata fields" do
  subject { described_class.new }

  it "responds to public_metadata" do
	expect(subject).to respond_to(:public_metadata)
  end

  it "responds to private_metadata" do
	expect(subject).to respond_to(:private_metadata)
  end

  it "can store data in public_metadata" do
	subject.public_metadata = { "delivery_required" => "no" }
	expect(subject.public_metadata["delivery_required"]).to eq("no")
  end

  it "can store data in private_metadata" do
	subject.private_metadata = { "preferred_delivery_time" => "n/a" }
	expect(subject.private_metadata["preferred_delivery_time"]).to eq("n/a")
  end
end

Checklist

Check out our PR guidelines for more details.

The following are mandatory for all PRs:

The following are not always needed:

  • 📖 I have updated the README to account for my changes.
  • 📑 I have documented new code with YARD.
  • 🛣️ I have opened a PR to update the guides.
  • ✅ I have added automated tests to cover my changes.
  • 📸 I have attached screenshots to demo visual changes.

@github-actions github-actions bot added changelog:solidus_api Changes to the solidus_api gem changelog:solidus_core Changes to the solidus_core gem labels Nov 27, 2024
@fthobe
Copy link
Contributor

fthobe commented Nov 27, 2024

Aims at solving #5951

@shahmayur001 shahmayur001 marked this pull request as ready for review November 27, 2024 20:27
@shahmayur001 shahmayur001 requested a review from a team as a code owner November 27, 2024 20:27
@boomer196
Copy link

Aims at solving #5951

Thanks for submitting this to the team! It is something I was hoping for as well. I have been watching the issue #5897 you opened.

@fthobe
Copy link
Contributor

fthobe commented Nov 28, 2024

Aims at solving #5951

Thanks for submitting this to the team! It is something I was hoping for as well. I have been watching the issue #5897 you opened.

Hey,
could you elaborate on your use cases in a couple of lines?
There are some discussions on the various ends and means of this PR.

@boomer196
Copy link

boomer196 commented Nov 28, 2024

Aims at solving #5951

Thanks for submitting this to the team! It is something I was hoping for as well. I have been watching the issue #5897 you opened.

Hey, could you elaborate on your use cases in a couple of lines? There are some discussions on the various ends and means of this PR.

Sure, basically I am hoping to have Solidus support something similar to the Metafields concept that Shopify has. I am just getting started with the platform, so I still have lots to learn, but when I saw the issue you opened, I felt like the "metadata" concept was something that would be a great addition to the core. I personally like the idea of having somewhere to store "structured" data on these objects that the core system doesn't really need to care about, but that storefronts can utilize.

@fthobe
Copy link
Contributor

fthobe commented Nov 28, 2024

Sure, basically I am hoping to have Solidus support something similar to the Metafields concept that Shopify has. I am just getting started with the platform, so I still have lots to learn, but when I saw the issue you opened, I felt like the "metadata" concept was something that would be a great addition to the core. I personally like the idea of having somewhere to store "structured" data on these objects that the core system doesn't really need to care about, but that storefronts can utilize.

What resources do you think need it most and why?

@jarednorman
Copy link
Member

Product, variant, order, line item, and shipment would be reasonable defaults. They are the most important core models and my experience they are the records that need additional fields in the broadest number of cases.

@fthobe
Copy link
Contributor

fthobe commented Nov 28, 2024

Product, variant, order, line item, and shipment would be reasonable defaults. They are the most important core models and my experience they are the records that need additional fields in the broadest number of cases.

Ok, given your pref for products and transactions also returns and RMA requests make sense at this point. Can you live with them + users and I stop bugging you?

@kennyadsl
Copy link
Member

kennyadsl commented Nov 29, 2024

Honestly, I don't think it's super important on which models we will add those metadata fields for the core. What's more important is creating a developer-friendly journey to add more of them when needed. What I envision for the success of this initiative is:

  • An easy way to add this metadata on any model. What about something like rails generate solidus:add_metadata Spree::Product? This task will generate a migration that adds the jsonb column to the corresponding table. It will probably do more with time, but that's already a good start.
  • Create a solid definition for the metadata. It might contain the type and the access level, something like:
{
  "key": "serial_number",
  "type": "string",
  "value": "123abc",
  "access": "public", // Can also be the roles which have permissions, like "admin"?
  "api": true // If we want this field to be included in the REST API payloads
}
  • Admin UI for resources with the metadata field. When the metadata is present, the Admin UI is smart enough to add a new section that allows operators to set those fields, with a different rendering based on their type. See what we did in the legacy admin for preferences here. Something similar would work, and can be extended if there are custom needs of extra types.

With these three elements, we have enough flexibility and we don't have to assume anything on where the fields are needed, which is without doubt something that dramatically changes from store to store.

@fthobe
Copy link
Contributor

fthobe commented Nov 29, 2024

@kennyadsl i really feel strongly about the admin part being a @MadelineCollier task. She's deep into that right now and it would take us much more time to do that. Can we slip that into her existing work?

@kennyadsl
Copy link
Member

She's deep into that right now and it would take us much more time to do that. Can we slip that into her existing work?

Yes, but it needs to be prioritized with the rest of the tasks in that case. By the way, the feature can live without the admin part, and we can add that later, isn't it?

@fthobe
Copy link
Contributor

fthobe commented Nov 29, 2024

For me it's an API feature with read only admin

@fthobe
Copy link
Contributor

fthobe commented Dec 1, 2024

Product, variant, order, line item, and shipment would be reasonable defaults. They are the most important core models and my experience they are the records that need additional fields in the broadest number of cases.

Given how addresses are made implications should be documented. For how it works now, would two addresses with different metadata create two different addresses or one address? @jarednorman

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
changelog:solidus_api Changes to the solidus_api gem changelog:solidus_core Changes to the solidus_core gem
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants