• Home

  • Custom Ecommerce
  • Application Development
  • Database Consulting
  • Cloud Hosting
  • Systems Integration
  • Legacy Business Systems
  • Security & Compliance
  • GIS

  • Expertise

  • About Us
  • Our Team
  • Clients
  • Blog
  • Careers

  • CasePointer

  • VisionPort

  • Contact
  • Our Blog

    Ongoing observations by End Point Dev people

    Spree: Working with Sample Product Data

    Steph Skardal

    By Steph Skardal
    July 21, 2010

    It’s taken me a bit of time to gain a better understanding of working with Spree sample data or fixtures, but now that I am comfortable with it I thought I’d share some details. The first thing you might wonder is why should you even care about sample data? Well, in our project, we had a few motivations for creating sample data:

    1. Multiple developers, consistent sample data provides consistency during development. End Point offers SpreeCamps, a hosting solution that combines the open source Spree technology with devcamps to allow multiple development and staging instances of a Spree application. In a recent project, we had a two developers working on different aspects of the custom application in SpreeCamps; creating meaningful sample data allowed each developer to work from the same data starting point.
    2. Unit testing. Another important element of our project includes adding unit tests to test our custom functionality. Consistent test sample data gave us the ability to test individual methods and functionality with confidence.
    3. Application testing. In addition to unit testing, adding sample data gives the ability to efficiently test the application repeatedly with fresh sample data.

    Throughout development, our standard practice is to repeatedly run rake db:bootstrap SKIP_CORE=1 AUTO_ACCEPT=1. Running bootstrap with these arguments will not create Spree’s core sample data set, but it will set the core’s default data that includes some base zones, zone members, countries, states, and roles, data that is essential for the application to work.

    Product Data Model

    Product data relationship in Spree

    The first data I create is the product data. As you can see from the image above, products data may have relationships with other tables including option_types, option_values, and taxons, or the tables that create has and belongs to many relationships between products and these elements.

    The most simple form of sample data might include one test product and its master variant, shown below. If you do not define a master variant for a product, the product page will crash, as a master variant is required to display the product price.

      id: 1
      name: Test Product
      description: Lorem ipsum...
      available_on: <%= Time.zone.now.to_s(:db) %>
      count_on_hand: 10
      permalink: test-product
      product: test_product
      price: 10.00
      cost_price: 5.00
      count_on_hand: 10
      is_master: true
      sku: 1-master

    Option Types and Option Values

    To expand on this, you might be interested in adding option types and values to allow for sizes to be assigned to this variant, shown below. The option type and option value data structure provides a flexible architecture for creating product variants, or multiple varieties of a single product such as different sizes, colors, or combinations of these option values.

      name: size
      presentation: Size
      name: Small
      presentation: Small
      option_type: size
      name: Large
      presentation: Large
      option_type: size
      product: test_product
      option_type: size
    # ...  master variant
      product: test_product
      option_values: small
      price: 10.00
      cost_price: 5.00
      count_on_hand: 10
      sku: 1-small
      product: test_product
      option_values: large
      price: 20.00
      cost_price: 10.00
      count_on_hand: 10
      sku: 1-large

    Taxonomies and Taxons

    Another opportunity for expansion on sample product data is the taxonomy structure, which is very flexible. A root taxonomy can be thought of as a tree trunk with branches; products can be assigned to any number of branches. If we assume you have multiple test products, you might set up the following test data:

      name: Category
      name: Brand
      id: 1
      name: Category
      taxonomy: category
      permalink: c/
      id: 2
      name: Jackets
      taxonomy: category_root
      permalink: c/jackets/
      parent_id: 1
      products: test_product, test_product2, test_product3
      id: 3
      name: Pants
      taxonomy: category_root
      permalink: c/pants/
      parent_id: 1
      products: test_product4, test_product5, test_product6
      id: 4
      name: Brand
      taxonomy: brand
      permalink: b/
      id: 5
      name: Brand One
      taxonomy: brand
      permalink: b/brand-one/
      parent_id: 4
      products: test_product, test_product3, test_product5
      id: 6
      name: Brand Two
      taxonomy: brand
      permalink: b/brand-two/
      parent_id: 4
      products: test_product2, test_product4, test_product6

    I also needed to include the taxons.rb (used in the Spree core sample data) to assign products to taxons correctly.

    Taxon.all.each{|t| t.send(:set_permalink); t.save}

    Example taxonomies created with Spree sample data

    Product Images

    My last step in creating Spree sample data is to add product images. I’ve typically added the image via the Spree backend first, and then copied the images my site extension directory.

    # upload Spree images
    # create sample image directory
    mkdir RAILS_ROOT/vendor/extensions/site/lib/tasks/sample/
    # copy the uploaded images to the sample image directory
    cp -r RAILS_ROOT/public/assets/products/ RAILS_ROOT/vendor/extensions/site/lib/tasks/sample/

    After uploading and copying the images over, I include the image information in assets.yml. The ID for each asset must be equal to the directory containing the multiple image sizes. For example, the directory RAILS_ROOT/vendor/extensions/site/lib/tasks/sample/1/ contains directories original, large, product, small, and mini with images sized respectively.

      id: 1
      viewable: test_product
      viewable_type: Product
      attachment_content_type: image/jpg
      attachment_file_name: blue_sky.jpg
      attachment_width: 1024
      attachment_height: 683
      type: Image
      position: 1

    And finally, I use a modified version of the Spree’s core products.rb file to copy over product images during bootstrap:

    require 'find'
    # make sure the product images directory exists
    FileUtils.mkdir_p "#{RAILS_ROOT}/public/assets/products/"
    # make product images available to the app
    target = "#{RAILS_ROOT}/public/assets/products/"
    source = "#{RAILS_ROOT}/vendor/extensions/site/lib/tasks/sample/products/"
    Find.find(source) do |f|
      # omit hidden directories (SVN, etc.)
      if File.basename(f) =~ /^[.]/
      src_path = source + f.sub(source, '')
      target_path = target + f.sub(source, '')
      if File.directory?(f)
        FileUtils.mkdir_p target_path
        FileUtils.cp src_path, target_path

    With my sample data defined in my Spree site extension, I run rake db:bootstrap SKIP_CORE=1 AUTO_ACCEPT=1 to create the above products, variants, and taxonomy structure. I commit my changes to the git repository, and other developers can work with the same set of products, variants, taxonomies including product images. During development, I also add unit tests to test model methods that interact with our sample data. An alternative to setting up Spree sample data described in this article is to dump entire databases and reimport them and manage the sample images manually, but I find that the approach described here forces you to understand the Spree data model better.

    Sample product image created with the sample data above.

    In addition to setting up sample product data, I’ve worked through creating sample orders, shipping configuration, and tax configuration. I hope to discuss these adventures in the future.

    ecommerce rails spree