I just published a new gem, inherited-attributes, for Active Record that works with the Ancestry gem to provide a tree data structure the ability to inherit attributes from their parent node, or farther up the tree. We've been using this technique for a long time to support configuring our multi-tenant application.
Once the gem is installed, its very simple to configure:
From there, you can access the effective attributes which look up the tree ancestry to find a value to inherit.
There are more options and examples in the gem, including has-one relationships, default values and support for enumerations.
We've found it helpful and writing a gem made this code much easier to test. What code do you have that would be easier to test as a gem or would be useful to others?
Showing posts with label rails. Show all posts
Showing posts with label rails. Show all posts
Wednesday, September 7, 2016
Friday, May 27, 2016
Capistrano Deploys without Swap
I work on a Ruby on Rails application that is deployed with Capistrano 3 to Amazon Web Services. We monitor our site performance with New Relic. About a month ago, we noticed that our deploys were causing a delay in request processing and a drop in Apdex.
Here is an example of what we saw during a deploy. The blue vertical lines are the deploy times and the green bar is how long a request spent waiting to be processed.

When we dug into it, we found that our servers were going into memory swap during the deploys. When we deploy with Capistrano, a new Rails process is started to pre-compile the assets. This pushes the memory usage over the physical memory limits. Here is the key graphic from New Relic. Note the swap usage just after 3:00 pm and the disk I/O at the same time.

You can see in the graph above how memory usage drops after the deploy so the solution to this was pretty straight forward: restart the servers first.
We're using Puma as our web server, so we added these lines to our deploy file. This causes a phased-restart to be sent before the deploy, freeing memory and allowing the asset compilation to have enough memory to run without using swap. Since Capistrano is based on Rake, its important to re-enable the phased-restart task after its run, otherwise it will only be run once.
Now our deploys run without causing requests to be queued. What tricks do you have for zero-impact deployments?
Here is an example of what we saw during a deploy. The blue vertical lines are the deploy times and the green bar is how long a request spent waiting to be processed.

When we dug into it, we found that our servers were going into memory swap during the deploys. When we deploy with Capistrano, a new Rails process is started to pre-compile the assets. This pushes the memory usage over the physical memory limits. Here is the key graphic from New Relic. Note the swap usage just after 3:00 pm and the disk I/O at the same time.

You can see in the graph above how memory usage drops after the deploy so the solution to this was pretty straight forward: restart the servers first.
We're using Puma as our web server, so we added these lines to our deploy file. This causes a phased-restart to be sent before the deploy, freeing memory and allowing the asset compilation to have enough memory to run without using swap. Since Capistrano is based on Rake, its important to re-enable the phased-restart task after its run, otherwise it will only be run once.
Now our deploys run without causing requests to be queued. What tricks do you have for zero-impact deployments?
Tuesday, February 10, 2015
Labeling Rails Enums
Rails 4.1 introduced ActiveRecord Enums, a handy little feature that lets you store an integer in a database column, but use symbols or strings in your code. Until today, I've been presenting these in select boxes with code like this:
This generates a perfectly acceptable select box if you don't need internationalization and the enum names you've picked are good enough to present to the user. If thats not the case, or you to change the presentation without changing the code, a new helper method leveraging Ruby's internationalization (i18n) features can be a good approach.
Keep reading for how I changed the presentation of enumerations in a drop down without changing my models or renaming the enumeration names.
This generates a perfectly acceptable select box if you don't need internationalization and the enum names you've picked are good enough to present to the user. If thats not the case, or you to change the presentation without changing the code, a new helper method leveraging Ruby's internationalization (i18n) features can be a good approach.
Keep reading for how I changed the presentation of enumerations in a drop down without changing my models or renaming the enumeration names.
Monday, April 7, 2014
Removing milliseconds in JSON under ActiveRecord 4.0
Rails 4.0 introduced a small bug in JSON generation with this pull request. The output format for times (ActiveRecord::TimeWithZone) in JSON changed to include milliseconds. Sounds good right? Well, not if your API clients crash trying to parse milliseconds. Unfortunately, Rails 4.0 didn't provide a configuration option for the timestamp precision in JSON output. What is a programmer under the gun to do? Upgrade to Rails 4.1 or get out your monkey and your patch and get to work?
Tuesday, March 25, 2014
Model is a poor scope name in Ruby on Rails 4
Upgrading from Rails 3.2 to Rails 4.0 is not a trivial task. Sure, there is a guide, but when you upgrade you'll probably be upgrading a lot of your gems, maybe your jQuery and jQuery-UI versions and then there are all the undocumented unintentional changes that can cause you grief. If you've got a good test suite (you have one right?) you'll catch a lot of these, but some will leave you scratching your head. This one tripped me up for a while: we had a very simple scope stop working in Rails 4.
The scope model below works in Rails 3.2, but fails in Rails 4 when used with an association:
The scope model below works in Rails 3.2, but fails in Rails 4 when used with an association:
Friday, March 14, 2014
Rails: updating an association through nested attributes does not touch the owner
I was a little surprised to discover that when you update an association through nested attributes, it won't touch the parent record. It makes sense when you consider that Rails is optimizing by not writing records that have not changed, but if were using updated_at on the model for caching you may be surprised.
For instance:
For instance:
Wednesday, March 12, 2014
Caching user records when using Authlogic
Today, I ran across another form of this issue with Authlogic. In short, every request in a Rails application using Authlogic with a User model that includes a last_request_at column will cause the updated_at column to change. This can break caching that is based on the last time a user was updated.
Labels:
authlogic,
cache-control,
caching,
controllers,
etags,
rails
Friday, January 10, 2014
Find the most popular capitalization of a word or phrase
Today, I needed to find the most popular capitalization of user entered product brands. Previously, I'd just used lowercase brands, something like this:
However, this was returning "whole foods" instead of "Whole Foods", which was considered more desirable.
Using window functions and common table expressions, this is what I came up with:
However, this was returning "whole foods" instead of "Whole Foods", which was considered more desirable.
Using window functions and common table expressions, this is what I came up with:
Tuesday, August 13, 2013
Adding Process ID and timestamps to the Rails Logger
For the last few days, I've been trying to debug a race condition between several Delayed::Job workers. After looking at log files for many hours, it became very frustrating to not know which one of my 3 workers was writing which statement. I finally found this post which almost did what I wanted.
To add process ids and timestamps to your Rails logs, you can add this as a Rails initializer (config/initializers/log_formatting.rb for instance) and restart your application / workers:
To add process ids and timestamps to your Rails logs, you can add this as a Rails initializer (config/initializers/log_formatting.rb for instance) and restart your application / workers:
Wednesday, May 8, 2013
How to write a simple Rails gem
Today, I wrote my first Ruby on Rails gem. It was a very simple refactoring of our code that I undertook when I needed to add the same functionality to a new model and I decided to do it as a gem instead of keeping it within our project. I wanted to see how it worked and this is what I ended up with. You can follow the Rails Guide, but it didn't cover everything I wanted to do.
Friday, August 31, 2012
Validating a User's Age in Rails
We ran across an interesting bug in our application recently: a user who was 18 years old exactly could not sign up for our service. This happened only in our production environment (not staging, development or test) and when we manually tested a number of dates, a user who was 18 years and 7 days old could sign up, but a user who was 18 years and 6 days old could not.
Subscribe to:
Posts (Atom)