Solidus E-commerce Platform

repository·main·Indexed 11 days ago

https://github.com/solidusio/solidus

A free, open-source e-commerce platform built on Ruby on Rails. Solidus provides a complete solution for managing stores, including a storefront, an admin interface, and a RESTful API. It features a rule-based promotions engine and a JavaScript SDK for API interaction.

Tokens
24K
Snippets
83
Records
117
Agent score
89%

What's inside Solidus

  1. Overview of Solidus architecture

    main

    Solidus is an open-source e-commerce platform built with Ruby on Rails. It is composed of several specialized gems that work together. While requiring the main solidus gem installs the full suite, you can choose to use only solidus_core if you want to build a custom frontend, admin interface, or API.

    Core components include:

    • solidus_api: Provides a RESTful API.
    • solidus_backend: Provides the Admin area.
    • solidus_core: Contains essential models, mailers, and classes.
    • solidus_sample: Provides sample data.
  2. Types of promotion benefits

    main

    Solidus Promotions provides three primary benefit types to adjust order totals:

    1. AdjustLineItem: Creates adjustments on line items. By default, it applies a discount to every line item in the order. Use line-item level conditions (like LineItemProduct) to restrict the discount to specific items.
    2. AdjustShipment: Creates adjustments on shipments. By default, it applies a discount to every shipment. Use shipment-level conditions (like ShippingMethod) to restrict the discount.
    3. CreateDiscountedItem: (Note: Mentioned as a type, but specific implementation details for this type are not provided in the source).

    For more efficient returns and bookkeeping, AdjustLineItem can use a DistributedAmount calculator to spread fixed discounts across all line items.

  3. Add Batch Actions to an index page

    main

    Batch actions allow administrators to perform operations on multiple selected records at once. To implement them, define a batch_actions method in your UI component. This method returns an array of hashes. Each hash must include:

    • label: The display name for the dropdown item.
    • icon: A Remix icon name.
    • action: The URL or path for the action.
    • method: The HTTP verb (e.g., :delete).

    When a batch action is triggered, it submits the selected record IDs via an id parameter. This allows the same controller action to handle both single-record and batch operations.

    Note: The batch_actions method is called in the context of the controller, so you can use controller helpers like solidus_admin.path_name.

    # In the component
    def batch_actions
      [
        {
          label: "Delete",
          icon: "trash",
          action: solidus_admin.delete_admin_users_path,
          method: :delete
        }
      ]
    end
    
    # In the controller
    def delete
      @users = Spree.user_class.where(id: params[:id])
      @users.destroy_all
      flash[:notice] = "Admin users deleted"
      redirect_to solidus_admin.users_path, status: :see_other
    end
  4. Solidus Admin Tailwind CSS coding style

    main

    The Solidus Admin Tailwind configuration follows these principles:

    • Minimal Customization: The configuration is kept as vanilla as possible to stay within default Tailwind boundaries.
    • Utility-First: Avoid custom classes where possible; use dynamic square bracket notation (e.g., top-[10px]) for occasional custom styles.
    • Template-Based: CSS classes are kept directly in the HTML templates of the components to simplify configuration.
    • Plugins: Customizations are primarily implemented via plugins to support both classes and variants.
  5. Files created by solidus_admin:tailwindcss:install

    main

    Running the installation task creates the following files in your application:

    • config/solidus_admin/tailwind.config.js: A configuration file that automatically imports the Solidus Admin's default configuration.
    • app/assets/stylesheets/solidus_admin/application.tailwind.css: The entry point where you can add your own CSS customizations.
    • Build tasks: Tasks to manually build the CSS or watch for changes to rebuild the target file at app/assets/builds/solidus_admin/application.css.
  6. Use StimulusJS Values for external state communication

    main

    StimulusJS values are the preferred way to represent state and communicate with the external environment. When a value changes, Stimulus triggers a callback (e.g., [name]ValueChanged()). This is the recommended way to trigger the render() pattern described in the coding style guide.

    import { Controller } from "stimulus"
    
    export default class extends Controller {
      static values = { open: Boolean }
    
      connect() {
        this.render()
      }
    
      show() {
        this.openValue = true
      }
    
      openValueChanged() {
        this.render()
      }
    
      render() {
        this.detailsTarget.hidden = !this.openValue
      }
    }
  7. Configure Search Scopes for index pages

    main

    Search scopes provide quick-access buttons to filter records by common criteria.

    Component Configuration

    In your UI component, define a scopes method that returns an array of hashes. Each hash requires:

    • label: The button text.
    • name: The scope name, which is sent as the q[scope] parameter.
    • default: A boolean indicating if this scope is active by default.

    Controller Configuration

    In your controller, use the search_scope helper (provided by SolidusAdmin::ControllerHelpers::Search). The helper takes a name, an optional default: true argument, and a block that returns an ActiveRecord scope.

    # Controller
    class SolidusAdmin::UsersController < SolidusAdmin::BaseController
      include SolidusAdmin::ControllerHelpers::Search
    
      search_scope(:customers, default: true) { _1.left_outer_joins(:role_users).where(role_users: { id: nil }) }
      search_scope(:admin) { _1.joins(:role_users).distinct }
      search_scope(:all)
    end
    
    # Component
    def scopes
      [
        { label: "Customers", name: "customers", default: true },
        { label: "Admins", name: "admin", default: false }
      ]
    end
  8. Configure Filters for index pages

    main

    Filters allow users to narrow down results using specific attributes. The index page uses the ui/table/ransack_filter component and relies on a filters method in your UI component.

    Each filter in the filters array must be a hash containing:

    • label: The name shown in the filter bar.
    • attribute: The Ransack-compatible attribute name.
    • predicate: The Ransack predicate (e.g., eq, in, cont).
    • options: An array of arrays in the format [['label', 'value'], ...] for selection-based filters.

    To enable filtering in the controller, ensure you include SolidusAdmin::ControllerHelpers::Search and call apply_search_to in your index action.

    # In the component
    def filters
      [
        {
          label: "Status",
          attribute: "status",
          predicate: "eq",
          options: [["Active", "active"], ["Inactive", "inactive"]]
        }
      ]
    end
  9. Voting mechanisms and weight for Stakeholders

    main

    Stakeholders use Open Collective contribution levels to determine voting power during meetings.

    Voting Requirements

    • Eligibility: An entity can only vote after a minimum of 3 months of recurring Open Collective contributions.
    • Weight Calculation: Voting weight is determined by the average monthly Open Collective contribution over the last 3 months.
    • Weight Cap: The weight of an entity's vote is capped at 1000, regardless of the contribution amount.
    • Representation: Each entity may invite up to 3 representatives to join the stakeholders group.

    Proposal Types

    • Single-choice proposals: Entities vote for one outcome. The outcome with the highest total weight wins. (e.g., "Spend $20,000 on SolidusConf venue").
    • Multiple-choice proposals: Entities can spread their total voting weight across multiple choices. The top N proposals (where N is decided by the proposer) are selected and prioritized by weight. (e.g., "Which features should we implement with OC funds?").
    • Asynchronous voting: If unable to attend a meeting, stakeholders can cast votes in the dedicated Slack channel.
  10. How UI vs. Page components work

    main

    Solidus Admin uses two types of ViewComponents to build the interface:

    • UI components: Small, generic, and reusable building blocks. They are located in app/components/solidus_admin/ui. Use these for elements like buttons or status badges that appear in multiple places.
    • Page components: Full-page components rendered directly by controllers. They follow the controller/action naming convention and are located in app/components/solidus_admin. For example, SolidusAdmin::OrdersController#index renders a component at app/components/solidus_admin/orders/index/component.rb.

    Decision Logic:

    • If a component is specific to one controller action: Use a Page component under the action's namespace (e.g., orders/index/payment_status/component.rb).
    • If a component is used by multiple actions in the same controller: Move it to the controller namespace (e.g., orders/payment_status/component.rb).
    • If a component is used by multiple controllers: Move it to the ui namespace or duplicate it if you want to avoid side effects when modifying it.
  11. Customize the solidus_storefront

    main

    The solidus_storefront is implemented as a Rails application template. During installation, it copies views, assets, routes, controllers, and specs directly into your project.

    Because the files are copied into your application rather than being managed as a library, you have full freedom to modify them. However, this means the storefront code will not automatically update when the template is updated. You are responsible for managing customizations and updates to the copied files.