cmar blog

Spree Engineer.

Fun With Shipments at SpreeConfDC

I opened SpreeConfDC with a talk on the current state of the Spree community and a discussion of the new Split Shipments in Spree 2.0. I’m really proud of the design and hard work the core team put into building this powerful feature.

Split Shipments was designed to help store owners of all sizes. The default behavior will be familiar to long time Spree users. But underneath lies a powerful set of constructs to help your store grow from a single location to a world wide enterprise.

This post gathers the video and slides for my talk. Thanks to Nate Edwards who recorded my talk and published it in 2 parts.

Bundle Searching

Jim Gay (@saturnflyer) posted a great tip for using The Silver Searcher to find the occurrence of a word within the gem dependencies for your project.

Bundler has had requests for search capabilities. Rule #2 of the Unix Philosophy is make each program do one thing well. The Silver Searcher is my current favorite searching tool. Its replaced grep and ack for all my code searching. Following rule #2, we don’t need bundler to search for us, we just need to compose it together with the best search tool.

Its a simple idea. Jim Gay wrote about it. I thought it was brilliant. I created an alias to make it easy to use:

1
alias bs="bundle show --paths | xargs ag"

Now, inside a project I can run ‘bs user’ to search for the word ‘user’ within all the gems included in my project. Is this fast? Yes! Inside a Spree sandbox - which has 81 gem dependencies - I can search for a common word like ‘user’ in 3.339s.

Thanks for the idea Jim!

Defacing Your Views

Deface is a gem to make targeted changes to views without altering the source file. It was developed by the Spree core team to help when multiple engines attempt to override the same view file.

Slides from my talk at the DC Ruby Users Group on Aug. 9, 2012.

Serving Additional Assets on the Pipeline

What is the problem?

Javascript and Stylesheet files required in application.js/css are not directly accessable in production. This is hard to detect during development because all assets are accessable through /assets/{name} in development mode.

The Rails Golden Path expects all javascript and stylesheet files to be declared in application.js/css. They are compiled together and minified in production. Once they are compiled together in production, the individual files are not directly accessable through /assets/{name}.

There are a couple situations where this causes problems. If you include a 3rd party javascript library that includes additional files, they may be accessable in development, but quietly fail in production.

We were using redactor.js which has 4 support files. It uses javascript to include the supporting files. We updated the declarations to /assets/en.js, /assets/pages.js etc. This worked fine in development. Redactor could access /assets/pages.js but in production when it was trying to request /assets/pages.js was returning 404.

We required pages.js at the top of application.js. It was getting compiled together with the rest of the javascripts, but Redactor quietly failed when it couldn’t access /assets/pages.js.

Why did this happen?

Rails assumes you will declare all your javascript and stylesheets in application.js/css. It also assumes in development that you want to access all the files directly through /assets/{name}. But once all the files are compiled to the /public/assets/application.js, you don’t need direct access to the individal files. The direct access we enjoyed in development is no longer available.

In production, some configuration options are set to improve performance:

# Disable Rails's static asset server (Apache or nginx will already do this)
config.serve_static_assets = true

# Compress JavaScripts and CSS
config.assets.compress = true

# Don't fallback to assets pipeline if a precompiled asset is missed
config.assets.compile = false

The last line says that if a file isn’t found in /public/assets don’t look in the project asset directories to find it. This is true in development. Any file burried in an assets directory can be found.

When you deploy to production, ‘rake assets:precompile’ is run. All the files declared in application.js will be compiled and minified into a single file in /public/assets. But the individual files will not be copied into /public/assets.

How do you fix it?

While you are in development mode, you can run ‘rake assets:precompile’. Then inspect your public/assets directory to see which files are copied over. If a specific file is not there; it will not be available in production.

If you need a specific file compiled and accessable from public/assets you need to declare it in ‘config/enviroments/production.rb’:

# Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added)
config.assets.precompile += %w( myfile.js )

If you need a javascript or stylesheet file to be directly accessable from public/assets, then you must add it to the array passed to config.assets.precompile. Once you add it, you can run ‘rake assets:precompile’ again to verify the file is copied over.

The trick is that the files are directly accessable in development mode so config.assets.precompile is not used. But without explictly declaring them in production.rb, they will not be available once you’ve deployed to production.

Stay on the Golden Path.

Hemisu Theme for Vim and Terminal

There is a new theme in town. Move over solarized. Make room for Hemisu. This has become my new vim and terminal theme for daily coding. I tried to use solarized; but I couldn’t fall in love.

Noah Frederick has created this amazing theme for Vim and Mac Terminal. It includes light and dark variations. I prefer the dark background unless I get stuck by the window at Starbucks. Then it is a simple “set background=light”.

hemisu preview

Url Reconstruction in Rails

Problem

In Rails, I needed to take the request url and redirect the user to a new host with additional query parameters while passing the original path and query parameters.

For example, if the original request looked like:

"http://www.mystore.com/cart?sort=desc"

I needed to redirect them to:

"https://mobile.mystore.com/cart?sort=desc&view=ipad"

While this could be done with fancy string manipulation, I figured there had to be a cleaner and less error prone way.

Solution

There is a great utility in Ruby Core to handle URL manipulation. Unfortunately, it isn’t well documented.

There is a kernal level method named URI which parses the full url and breaks it down into parts

# request.url = http://www.mystore.com/cart?sort=desc
uri = URI(request.url)
puts uri.host # www.mystore.com
puts uri.scheme # http
puts uri.query # sort=desc

To swap the host and scheme was easy enough

uri.host = "mobile.mystore.com"
uri.scheme = "https"

To modify the query parameters, we had to consider the possiblity of no parameters. In that case, the uri.query would be nil. The query parameters are only broken down into a string, so we have to split, add and join them back together.

query = uri.query ? uri.query.split('&') : []
query << "view=ipad"
uri.query = query.join('&')

Then we just have to reconstruct the url and redirect the user

redirect_to uri.to_s # https://mobile.mystore.com/cart?sort=desc&view=ipad

Conclusion

There is always a cleaner way.

Spree Product Groups Removed

We have removed Product Groups from the core Spree project. This was a rarely used feature; but, the code was fairly complex. In an effort to keep Spree lean, the code was extracted and moved to an extension.

The commit to Spree Master will be part of the 1.1 release. If you are using Product Group functionality, then you’ll want to include the extension in your Gemfile after ‘spree’.

1
2
gem 'spree'
gem 'spree_product_groups', :git => 'git@github.com:spree/spree_product_groups.git'

It has not been released as a gem, so you’ll have to declare it with a reference to the git repository.

All previous Product Group functionality will be restored by the extension.

Call Super in Method_missing

Recently, I was refactoring some code and came across this seemingly innocuous method_missing override:

1
2
3
def method_missing(name)
  @properties[name]
end

I’ve seen this quick hack more often then I’d prefer. It allows easy reader access to the values stored in the hash.

1
2
3
4
5
#instead of this
object.properties[:keywords]

#you can call this
object.keywords

The keywords method is not found; so, method_missing is called. The missing method name is passed to the hash and the value is returned. But if the key does not exsist, then nil is returned. The side effect is that any method name can be called on the object and nil is returned. Even inncorect method names will happily return nil. This can propogate misspelled method names throughout the code.

Overriding method_missing is a great way to quickly add convenient reader methods to your object. But method_missing has an important job. By not calling super, your changing the assumed behavior native to ruby. Misspelled method names or methods which do not exist should raise an exception. This is the expected behavior.

The correct way to override method_missing is to check if the key exists; otherwise call super.

1
2
3
4
5
6
7
def method_missing(name)
  if @properties.has_key? name
          @properties[name]
  else
      super
  end
end

Debugging Spree 1.0 With Ruby 1.9.3

Here are the steps you need to get ruby-debug to work with Ruby 1.9.3p125 in the Spree sandbox.

Setup

  • rvm 1.10.3
  • ruby 1.9.3p125
  • Spree 1.0.x

Installing Gems

1
2
3
4
5
6
7
8
# download the source code for pre-release version of linecache, then install locally
curl -OL http://rubyforge.org/frs/download.php/75414/linecache19-0.5.13.gem
gem install linecache19-0.5.13.gem

# download the source code for pre-release version of debug-base, then install locally
# using rvm installed source code (/Users/cmar/.rvm/rubies/ruby-1.9.3-p125/rubies/src)
curl -OL http://rubyforge.org/frs/download.php/75415/ruby-debug-base19-0.11.26.gem
gem install ruby-debug-base19-0.11.26.gem -- --with-ruby-include="${MY_RUBY_HOME/rubies/src}"

Modify Spree Gemfile

1
2
3
4
5
group :development do
   gem 'linecache19', '0.5.13'
   gem 'ruby-debug-base19', '0.11.26'
   gem 'ruby-debug19', :require => 'ruby-debug'
end

Running Spree Sandbox

After you update the Spree gemfile, you can create a sandbox and run with the debugger

1
2
3
4
5
6
7
git clone https://github.com/spree/spree
cd spree
# edit Gemfiile (above)
bundle
bundle exec rake sandbox
cd sandbox
rails s --debugger

Slides From SpreeConf 2012 NYC

Here are the slides from my talk at SpreeConf 2012 in New York City. I covered the new Preferences for Spree 1.0 and their usages in payments and promotions. I went pretty deep with a lot of interaction diagrams.

Demo Source Code on Github