I came across puma reading Mike Perham’s blog and was instantly intrigued. Its a threaded server that runs using one copy of your app vs the way Passenger does it by spinning up about 2 or more copies of your app as processes forked from a parent process and distributing requests to each one in turn to keep them all busy.
The thing that jumped out at me was the promise of memory savings by going from 5-6 processes in memory to 1. I run a 768MB VPS with linode. With Passenger I was running 500-600MB RAM usage because of the distinct ruby processes that Passenger forks to handle requests to your server. (Each process was about 80M and I was running 5 or 6 of them)
There is no Apache documentation for proxying to puma, but after looking at this example by the Phusion guys about how to proxy Apache to Passenger Standalone, I figured out a nice little step-by-step way to quickly try out puma to see if you like it or not.
This assumes you’re already running Phusion Passenger with Apache in production
- gem install puma on your server, don’t add it to your gemfile
- Now mosey on over here and get Apache Proxy installed,
/etc/apache2/mods-available/proxy.conf will probably already be there for you so all you’ll probably have to do is
- Alright, now go find your apache.conf or httpd.conf file and comment out all the passenger related stuff, things like …#LoadModule passenger_module /opt/ruby-enterprise-1.8.7-2010.02/lib/ruby/gems/1.8/gems/passenger-3.0.7/ext/apache2/mod_passenger.so
… and other Passenger configuration directives (PassengerMinInstances for example)
- Now go find the file where you defined your virtual host, for me it was in
- Make it look like this (comment out all your other stuff for now, you can add other cool crap once you get it working)
ProxyPass / http://127.0.0.1:9292/
ProxyPassReverse / http://127.0.0.1:9292/ #the trailing slashes here are VERY important
- now go to your app root and run
puma -e production
- restart apache and navigate to your app and you should see it load right up
Couple of things to note
- you will probably want to add a line to your production.rb that is simply
It basically eager loads your app (vs autoloading the sections it needs) to help avoid problems with threading rails, you can learn more about config.threadsafe! in this very detailed post
- I went from using close to 600MB of RAM to just 350MB and it was blazing fast!!!
Then I moved over to using puma with nginx and Ruby 2.0.0 (post coming up) and it was even faster!
- If you think you want to keep puma around then I encourage you to install the puma prerelease (currently 2.0.0.b4) by running
gem install puma –prerelease
once you do that, then you can run puma as a daemon by doing
puma -d -e production
otherwise you’ll have to have a terminal window open running it the way you run webrick/thin in dev
- New relic reporting won’t work out the box unless you use the prerelease version
I hope you like puma as much as I do.
In very unscientific tests Ruby 2.0 is 60-70% faster than 1.9.3.
PS: I couldn’t get my test suite to run in Ruby 2.0.0 but I managed to run the very simple
“time bundle exec rake environment” test
The average was
- 7.74s for ruby 2.0.0
- 11.8s for ruby 1.9.3-p368, a 65% speed improvment, right in line with the results from the gist
- 17.07s for rubinius 2.0.0 (1.9 variant) … yeah thats slow
We just moved to the latest Test::Unit, which uses MiniTest under the hood. Because of that, I wanted to take advantage of the new MiniTest::Spec DSL to get RSpec-like syntax in Test Unit.
The problem is, when I went to the try using it, I started getting all sorts of strange duplicate key/column errors.
At first I thought it was because of a recent upgrade I had done from Postgres 9.1 to 9.2, but as I dug in deeper, I realized it was my new Spec Test. We are running our tests in transactions that we rollback on the completion of each test, MiniTest::Spec wasn’t doing this and causing all the test errors.
After hours of digging I finally found the solution to the minitest duplicate key issue here. I hope it saves you some time. Definitely did for me!
PS: The other alternative that was pointed out to me was to simply use the minitest-rails gem. I tried it but it didn’t work cleanly right out-the-box for our setup (errors in tests, etc). I was too tired to fix it up, so I’ll kick the can down the road till I need to revisit this issue, probably in upgrading to Rails 4.
I learned from my mistake in falling behind when Rails 3 came behind, so I’m trying to get a jump on Rails 4. Skip straight to my summary if you don’t want to watch the 20 minute video right now
- Array and hstore support for Postgres
- Model.all is now an ActiveRecord Relation vs loading records immediately, Model.all.to_a now gives you former Model.all behavior
- Model.scoped is deprecated
- Model.none (no idea why anybody would use this)
- Model.not.where() inverts/negates the scope/where clause
- chaining scopes to an active Relation object is possible with an ! at the end of the scope. This option mutates the current Relations object for you, so you don’t have to assign the new chain to a variable
- Model.find_by, Model.find_or_create_by now accepts a hash so that its Model.find_by(name: “Hello), stops dependence on method missing implementation of find_by_xxxx
- Model.find_or_create_by is deprecated but Model.find_by is not
- using an object as an Active Model object is easier, just include a module, used to be a bit more tedious
- in scopes you could pass in another scope as a second argument, now it has to be a callable object (like a lambda) this is to avoid passing in something Dynamic like Time.now by accident
- Model.update_attributes method has been renamed to just Model.update (probably to avoid confusion with update_attribute?)
- the placeholder index.html file doesn’t exist anymore, dynamically generated
- before_filter is renamed to before_action … won’t be deprecated though
- update action responds to PUT or PATCH, PUT might be deprecated
- support for strong parameters is built right in ( checkout Railscast Ep 371), better option that attar_accessible
- means that we don’t need attr_accessible in models but if you want that behavior still, you can use the protected attributes gem
- concerns. Designed to add modules which encapsulates behavior that you want to share among controllers/models. Ryan doesn’t care much for it, will add it in as needed in his apps (see Railscast ep 398)
- ActionController live (will be covered in future ep)
- collections. collection_check_boxes, collections_radio_buttons. Can be used to handle associations or array attributes in forms more easily.
- helpers for html5 input types. date_field vs date_select (for example). Spits out html5 date control or just select input depending on the browser
- support for custom templating with .ruby extension. Probably limited usage for html, but useful for json (more in ep 379)
- cache Digest/Russian doll caching (more in ep 387)
- concerns, helps remove duplication in routes.
- match method is no longer supported (wtf?) have to change them from that to the right verb i.e get/patch/post
- if you supply constraints to a route its going to turn into a default attribute when you generate the url, so it forces the url to match the constraints. very cool
- new exception page, if its a routing error, you get all the routes in the app listed after it (kinda silly if you ask me)
- you can get all the routes in the app from /rails/info/routes
- ability to specify console config options in application.rb with console block
- config.eager_load is default in production.rb so the entire app is loaded on start instead of autoloading, that helps keep Rails thread safe
- config.threadsafe! has been deprecated (more in ep 365)
- test directory is now structured differently, controllers, models, mailers vs functional, unit directories (big one here)
- Test::Unit now uses minitest under the hood which allows us to use rspec like syntax in Test::Unit
- Active Resource
- Model Observers
- Page & action Caching
- Disabling cache by default
- all available as gems if needed
Recently, I’ve been working hard to plug one of the biggest holes in my game … testing. I stumbled across this article, which helped make a lot of things clear for me, with respect to mocking and its relation to Unit testing.
This is partially due to the fact that most geeks don’t actually know what a unit test is. They think that testing the methods of a specific class constitutes a unit test, but that’s only part of the story. A unit test test is when you test the methods of a specific class in isolation, and the difference is critical. You know how some people call us “computer scientists”. Yeah, well this is the science part.
If you’re not doing this, you are not unit testing. That’s not meant to deride what you’re doing. I mean that as a literal statement of fact. Anyone, for example, who is using the built in Rails “unit” testing framework with fixtures (or FactoryGirl fixtures) is guilty of this. No test that relies on a separate class, or API, or interfaces with a database in any way is a unit test. It is an integration test (some people call them functional test), and when something goes wrong it is just a matter of time before it misleads you.
Enjoy the article – The Thing about Mock Objects
The bane of any ruby/rails developer on a windows box (apart from piddling performance) is seeing the dreaded …
‘gem install error – ‘cl’ is not recognized as an internal or external command’
Devkit, a tool used by the folks who create the Windows Ruby Installer of each version of ruby helps you with (most) gems that need to be built natively.
Muchos Gracias to them for graciously providing it to us.
In Authlogic, if you use a password confirmation field (when creating a new user perhaps), there is an error message that shows up for that field if the User model does not validate.
is too short (minimum is 4 characters)
Seems simple enough to turn off, but I almost went mad trying to figure out how do this without completely turning off password authentication.
class User < ActiveRecord::Base acts_as_authentic do |c| c.merge_validates_length_of_password_confirmation_field_options :allow_blank => true end end
PS: It’d be nice to get all the configuration options for Authlogic in one place, with better documentation for each one.
Maybe I should get on that … it is open source software after all
Just go to the the rails directory that corresponds to this one on your computer (This is on a windows XP machine, but you should be able to figure out the right path on your machine)
Open up server.rb
And edit the line that says
server = Rack::Handler::Mongrel
server = Rack::Handler::Thin
change_table :products do |t| t.timestamps end