Often during development it’s useful to have realistic data to get a sense of how an app would behave in the wild. Seed data is one useful method to get going pre-launch, but production data is always preferable.
However production data can contain sensitive user information, which is useful for the dev team but nerve-wracking for those looking to avoid a PR disaster, say if sensitive equipment is left lying around in bars.
One solution we’ve used recently to anonymize client data is to obscure the relevant content using the Faker gem and the rand function.
User.all.each do |user| genders = ['male', 'female'] user.update_attributes!( :born_on => rand(50*365).days.ago :email => (rand(1000) + 100).to_s + Faker::Internet.email, :first_name => Faker::Name.first_name, :gender => genders.rand, :last_name => Faker::Name.last_name) endFaker’s seed name list is limited and leads to duplicates quickly. You can further randomize fields by prepending random numbers as above.
Anonymizing company names is also straightforward. Faker provides fun catch phrase generators of fake business jargon such as “Inverse 24/7 utilisation”
Company.all.each do |company| company.update_attributes!( :description_html => Faker::Company.catch_phrase, :name => Faker::Company.name, :twitter_username => Faker::Internet.user_name, :url => 'http://' + Faker::Internet.domain_name) endTo anonymize location-based data is trickier - randomizing the latitude/longitude values would look scattered on a map view. One method is to keep the (lat, long) pairs together but randomize them across the column by loading them into an array, shuffling, then replacing the existing data. Here we use a modified verison of the previously-mentioned inject method.
location_array = Location.all.inject([]) do |result, location| result << [location.lat, location.lng] end.shuffle Location.all.each do |location| lat, lng = location_array.pop location.update_attributes( :city => Faker::Address.city, :extended_address => Faker::Address.secondary_address, :lat => lat, :lng => lng, :phone => Faker::PhoneNumber.phone_number, :postal_code => Faker::Address.zip_code, :state => Faker::Address.state_abbr, :street_address => Faker::Address.street_address ) endFaker generates numbers with prefixes and extension numbers, such as “+1 (877) 976-2687 x1234”. For a strict (XXX-XXX-XXXX) format, use:
:phone => (rand(900) + 100).to_s + "-" + (rand(9000) + 1000).to_s + "-" + (rand(9000) + 1000).to_sComplete code available at this Gist.
See, what we have here is an Enumerization of the Virtus wherein Pelusa, the Deploy Doorkeeper, gets Kronk. It's on Ruby5... and pudding pops.
Listen to this episode on Ruby5
This episode is sponsored by Top Ruby Jobs
If you're looking for a Ruby job or for top Ruby talent, then you should check out Top Ruby Jobs. Top Ruby Jobs is a website dedicated to the best jobs available in the Ruby community.
Clean your Ruby Lint with Pelusa
Last week, Josep Bach released Pelusa, which is a static analysis, lint-type tool for Ruby. It uses Rubinius to inspect the structure of your code and compares it to best practices, such as method size, demeter violations, conditional complexity, and more.
Compare server responses with Kronk
Jeremie Castagna has been working on a library called Kronk which can be very useful for API developers. With Kronk, you can read server responses in multiple formats (like JSON or XML) and compare both their structure and content. It'll give you early indications if your API is becoming out-of-sync between response formats.
Create enumerated attributes with Enumerize
Sergey Nartimov let us know about Enumerize, a library that twinslash recently released for creating enumerated attributes with i18n support for both ActiveRecord and Mongoid.
Get common recipes with capistrano-deploy
Capistrano-deploy is an abstraction of common deployment recipes that are made available for you to use, such as using bundler, working with Rails assets, RVM, and more. So, if you're using Capistrano, check it out.
Virtus – intelligent attributes for Ruby objects
Piotr Solnica and Dan Kubb are in the process of extracting a bit of DataMappers properties implementation into a stand alone library called Virtus. With it, you can set coerced attributes (properties) on plain old Ruby objects or other ORM-backed Ruby classes. It supports simple, local objects and even collections of other coercible data types.
Create an OAuth2 provider with Doorkeeper
Doorkeeper is a gem created by Applicake which makes it easy for you to turn your Rails application into an OAuth2 provider. This could be useful if you want other developers to build against your API to perform acts on behalf of your users (think Twitter or GitHub).
Let’s say you want to update capybara and capybara-webkit. You’d normally type this:
gem update capybara capybara-webkitBut you’re busy, you don’t have time to type “capybara” twice. Let’s see what tab completion has for us:
gem update capybara{,-webkit}The bracket expression expands to the same thing as above because the brackets expand to "capybara" + "" and "capybara" + "-webkit". If you’re in ZSH, you can press the TAB key (gem update capybara{,-webkit}) and it will expand the expression for you inline. Bash users, this will still work for you, even without the neat TAB trick.
You can set the name of the current Ruby process, the one that you would see from the ps command for example.
Simply assign a string to the global variable $PROGRAM_NAME:
This is a great way for long running scripts or daemon processes to communicate status information to people who are looking in on them.
5.times do |i| $PROGRAM_NAME = "Ruby Quicktips Example: On iteration #{i}" sleep 5 # I'm really busy!! endExecute something like this in your terminal:
ps x | grep QuicktipsThis tip was submitted by Jesse Storimer.
Our little copycopter_client library, which talks to the amazing Copycopter app (which, in my opinion, is the best thing since sliced bread), got some infrastructure cleanup from Gabe Berke-Williams (gabebw) around themes like Travis CI (91ac190) and bundler (612fc4e), plus sorting the blurbs (500dac7). Chris Hunt (huntca) swooped in with the ability to export to YAML (7d44323, 77b28bb, cf951f1, 2955575), booyah!
factory_girlVersion 2.6.0 of factory_girl is out (2d19c46), with work by Joshua Clayton (joshuaclayton). The docs got an update, including an example of how to create a has_many association factory easily (9c6c252). The new :method option has been renamed to :strategy, following thoughtbot’s recent obsession with design patterns (791591b).
capybara-webkitMarching right along, capybara-webkit version 0.10.0 is out (6d37e48). Marc Schwieterman (marcisme) added a current_url method (caa86b7 and 5eacd08) and reset! method (eaec979). Igor Zubkov (biow0lf) fixed some specs (9eb8e55)! Matthew Mongeau (halogenandtoast) abstracted out the make, qmake, and spec paths into environment variables (4a6b766). Jason Petersen (jasonmp85) fixed a bug where select_option and unselect_option methods were mutating the underlying HTML in ways the W3C were very unhappy with (` element. This attribute is meant to be used solely as the marker for which ``(s) is (are) the default selection(s) in a (multi-)`` element. The actual _selectedness_ of an `` should be tracked using its `selected` **property**. Read [the spec][] for more info. This change removes any code which modified the `selected` attribute of `` elements, which leaves only the code that modifies the `selected` property. In addition, `Node#value` needed to be changed to return `` elements whose selectedness is true rather than just those with a `selected` attribute. The tests introduced in the previous commit now pass. [the spec]: http://dev.w3.org/html5/spec/Overview.html#the-option-element">2fef844 and ` element, so modifying it will necessarily break the behavior of reset buttons in forms. In addition, the existing code leaves this attribute set on existing `` elements, which can put the page into an invalid state. [HTML5 spec]: http://dev.w3.org/html5/spec/Overview.html#the-option-element">acd6e47).
appraisalOur wonderful little appraisal gem got a documentation patch from Kate Gengler (kategengler) explaining that the Appraisals file must be named Appraisals (adec57d). Ryan Bigg (radar) added the option of loading the Gemfile from an environment variable, BUNDLE_GEMFILE (e41fdfc). Prem Sichanugrist (sikachu) released version 0.4.1 (4da9c66).
clearanceDespite the lack of a release this week, Dan Croak (croaky) put clearance on Travis CI (3430e88 and 91674c6).
bourbonNeat improvements for bourbon, as always. Gabe Berke-Williams (gabebw) fixed Ruby 1.8 support (45f6806). Frank (frankzilla) added clearfix (df3b82c, ac172bc, 980035c, and a1825ee). Patrick Bougie (pbougie) fixed border-radius for older Mozilla (f734db4). Kyle Fiedler (kylefiedler) added a flexible grid (0db24f5, 2bb0f63). Thibaut (Thibaut) fixed a bug in the box shadows (60292da).
dieselInfrastructural changes to diesel this week, as Prem Sichanugrist (sikachu) made it work with the latest version of Rails, trimmed its dependencies down, and fixed it on Travis CI (6481f8f, = 0.8.3 on Ruby 1.9.3 when generate the application. As Appraisal cannot specify gems based on Ruby version yet, we should just remove turn from our gemfile.">2dc7427, caadb84, 183762d, af52bbb, 5f57595, 4f115e9, bb4e627).
paperclipIt was bug fix week in paperclip land, as we wage on in the constant battle to keep the Issues count at 0. Prem Sichanugrist (sikachu) made sure we check for class_attribute before calling it, fixing a problem in one specific verion of Rails (4b79530); handled the case where the S3 object does not exist (56012bf); found and fixed a case where the style name was not a symbol (9ad074a); and cleared off an annoying warning from a redefined constant in the test suite (7045e29). Chris Apolzon (apolzon) meanwhile fixed a bug where stderr was leaking out in undesired ways (58671eb).
We've been tuning some parameters on the ArildBot 2000 and it sounds almost human in this episode.
Listen to this episode on Ruby5
This episode is sponsored by New Relic
Hey, we heard you liked monitoring... so we added some monitors to your monitoring so you can monitor more with your monitors.
If you can measure it, NewRelic can tell you about it. And for a limited time you'll get a free copy of Eric Reis' 'The Lean Startup' to help you figure out what to do with all that info.
ror-ecommerce
David Henner released the ror_ecommerce project, a rails 3.2 boilerplate that can be used as a platform to build your own e-commerce sites.
simple_nested_form
Ryan Bates recently released simple_nested_form, a Rails gem for conveniently managing multiple nested models in a single form.
Templating shootout
Veena Basavaraj, an engineer at LinkedIn, recently shared this story on a shootout between 18 different client-side tempting solutions, including mustache, handlebars, liquid, and a bunch more.
watu_table_builder
A gem with a long history, recently revived to use bundler, run in Travis-ci, and pull in some feature branches, table_builder is to tables what form_builder is for forms. Use ruby composable ruby blocks to maintain your table tag structure for you.
FuzzyTime
Have you ever wanted your ArildBot 2000 to say things like "Quarter past 5" instead of 5:16:22pm? Fuzzytime gives that to you. Its a nice complement 'time_ago_in_words'.
dummy_image
Dummy Image is a rack mount that generates images on the fly based on parameters in a url. Perfect for generating placeholders while you wait on your designer.
sinatra-cache
If you've ever been writing an app with Sinatra and wished you had something like the page and fragment caching in Rails, this gem is for you.
simple_form_fancy_uploads
Are you using Simpleform? Are you handling file uploads with CarrierWave? Then check out this gem of custom simple_form inputs that make it easy to do file uploads - including an image preview.
Ruby
Ruby 1.8.7p358 and 1.9.3p125 have been released with a security fix, support for GCC 4.7, and a few other small changes.
Let’s talk about Enumerable#inject. It’s special to me. In other cultures it’s called foldl, foldLeft, reduce, catamorphism, or bananas (PDF). We got our name from Smalltalk, which got it from, I dunno, a folk song?
Inject is an abstraction over structural recursion. For examples, imagine a list were defined like this:
class EmptyList end class ConsList def initialize(first, rest) @first = first @rest = rest end end factorials = ConsList.new(1, ConsList.new(2, ConsList.new(6, ConsList.new(24, ConsList.new(120, EmptyList.new)))))Computing the length of the list is simple:
class EmptyList def length 0 end end class ConsList def length 1 + @rest.length end endComputing the product of the list is simple, too:
class EmptyList def product 1 end end class ConsList def product @first * @rest.sum end endThere’s a common pattern here: we have a base case (0 and 1), an enumerable (EmptyList and ConsList), and a combining method (lambda {|x,xs| 1 + xs} and Fixnum#*). Let’s write a method to abstract over this:
class EmptyList def inject(base, &block) base end end class ConsList def inject(base, &block) block.call(@first, @rest.inject(base, &block)) end endNow that we’ve abstracted this out (in 2009 we said “DRYed this up”, and then immediately punched ourselves in the face) we can use it:
class ConsList def length inject(0){|_, count| 1 + count} end def product inject(1){|number, running_product| number * running_product} end end(Note that Ruby got the arguments backward. Oh well.)
An underlying theme to inject is that there exists a class with a base case and a combining method. Some other examples are: 0 and Fixnum#+; 1 and Fixnum#*; [] and Array#push; true and &&; lambda{|x|x} and lambda{|f, g| lambda{|x| f(g(x))}} (the identity method and method composition); and so on. These are called monoids, and that’s awesome because now we have a name for them.
“Oh sure, just inject over the method monoid,” you say to your coworker, and she’s like, “oh, duh” and types it out:
class Composition def initialize(f, g) @f = f @g = g end def compose(g) Composition.new(self, g) end def call(x) @f.call(@g.call(x)) end end id = lambda{|x| x} twice_the_sine_plus_one = [lambda{|x| x+1}, lambda{|x| x*2}, lambda{|x| Math.sin(x)}] new_method = twice_the_sine_plus_one.inject(Composition.new(id, id)) do |result, f| result.compose(f) endJoin me next time when I talk about monoids closed over the category of endofunctors!
One of our goals for Trajectory is to provide a guided path to a better way to develop software. When possible, we let that influence the way Trajectory works.
Iterations are each one week.
You can run a command every time you change directories in zsh with the chpwd function:
export CURRENT_PROJECT_PATH=$HOME/.current-project function chpwd { echo $(pwd) >! $CURRENT_PROJECT_PATH } current() { if [[ -f $CURRENT_PROJECT_PATH ]]; then cd "$(cat $CURRENT_PROJECT_PATH)" fi } currentThis will write the current directory to a hidden file in $HOME; opening a new terminal will automatically cd to that directory.
This does not work:
class Foo private def self.bar end endFoo.bar will be public.
To make it private, you can use Module#private_class_method:
…or define it differently:
class Foo class << self private def bar end end endThis tip was submitted by two-bit-fool.
The icebox is a place where stories go to die. It’s typically used to hold two kinds of stories:
Read the full post on the Trajectory blog, Mission Control.
The captured wildcard in a Rails 3 route can be used in the redirect method:
match 'via/:source' => redirect('/?utm_source=%{source}')This example is intended to improve metrics for customer acquisition campaigns. utm_source is for Google Analytics, which KISSMetrics logs as Ad Campaign Hits.
The URLs are now friendlier for sharing:
/via/email /via/twitter /via/search-ads /via/blog-adsWhen the user clicks them, they’ll be redirected to:
/?utm_source=email /?utm_source=twitter /?utm_source=search-ads /?utm_source=blog-adsThe URLs are also encapsulated. If the Google Analytics params need to change, the developer can edit config/routes.rb and deploy. All past routes will still work.
Ever since I started to work with Ruby in 2008, I’ve always assumed that it was an interpreted language like PHP or Javascript – in other words, that Ruby read in, parsed and executed my code all at runtime, at the moment my program was run. This seemed especially obvious since the default and most popular implementation of Ruby is called “MRI,” short for “Matz’s Ruby Interpreter.” I always thought it was necessary to use an interpreter to make all of the dynamic features of the language possible…
It's Valentine's Day and on this episode we Deliver Newman to the Lion, while the Little Guys go on a Anonymous donation Spree for Travis CI!
Listen to this episode on Ruby5
This episode is sponsored by Top Ruby Jobs
If you're looking for a Ruby job or for top Ruby talent, then you should check out Top Ruby Jobs. Top Ruby Jobs is a website dedicated to the best jobs available in the Ruby community.
Spree has just released version 1.0
The open source Rails-based e-commerce platform, Spree, has just recently released version 1.0. After five years of platform development, this release contains 1500 new commits since the last one from 35 different contributors.
Newman – A microframework for email-oriented applications
Mendicant University’s Gregory Brown recently released Newman, a micro-framework designed to help build email-oriented Ruby applications. It can automatically respond to incoming email, providing Tilt-based templates, filter email activities by attributes, and a lot more. It's NOT PRODUCTION STABLE, yet, but it could be worth a peek if you want to integrate an app with an inbox.
Deliver - Heroku-like deployment
Gerhard Lazu just let us know about Deliver, a command line utility for doing a Heroku-like deployment on non-Heroku systems. It's built for *nix server environments and is fairly easy to configure. Deliver is an alternative to automated deployments using Capistrano.
Ruby 1.9.3 via RVM on MacOS X Lion
Over on Unfolding Code, Marius Butuc wrote up a step-by-step guide on how to install Ruby 1.9.3 on OS X Lion using rvm. Apparently, the GCC installer is the way to go, but if you'd like more details, check out his post.
Anonymous Blocks as function Arguments in Ruby
Stephen Ball put together a great article describing how to use blocks as function arguments, how to call any method in Ruby with a block, and how to hand blocks around using the ampersand and call. If blocks are confusing to you, see his post and become enlightened.
SOA for the Little Guys
Mike Pack, just yesterday, wrote up a thorough introduction to Service Oriented Architectures in which he targeted, “the little guys.” He explains the costs and benefits of SOA, as well as walks you through an example of how you might split up an existing application to take advantage of it.
Travis CI Fundraising
The Travis CI team is still alive and kicking, and looking to add even more features to the service (like private repo support, pull request testing, and more). If you'd like to help, they're looking for donations to help them spend more time on the project and continue to make it open and available to public projects. Even if you don't use Travis directly, you probably use an gem or other open source project that benefits from its continuous testing, so please consider giving them a small donation.
This snippet simply clears your logs when they are too large. Every time you run rails server or rails console it checks log sizes and clears the logs for you if necessary.
# config/initializers/clear_logs.rb if Rails.env.development? MAX_LOG_SIZE = 2.megabytes logs = File.join(Rails.root, 'log', '*.log') if Dir[logs].any? {|log| File.size?(log).to_i > MAX_LOG_SIZE } $stdout.puts "Runing rake log:clear" `rake log:clear` end endThis tip was submitted by pahanix.
After doing TDD full time for years, I have a hard time writing code without a test. One example that I find particularly difficult is writing data migrations.
Some schema changes require more than just setting a default value for all existing rows. For example, let’s say you have this schema:
create_table :users do |table| table.string :email table.string :encrypted_password end create_table :posts do |table| table.integer :user_id table.boolean :published table.string :message endIf you want to find the top ten users based on the number of published posts, you can do a JOIN with a COUNT and a GROUP BY clause, but over time that could get slow or just annoying, so you decide to add a cache column:
add_column :users, :published_posts_count, :integer, :default => 0, :null => falseYou add code to populate the column and all the tests pass, but of course there’s a big problem: every existing user in production will report zero published posts. That means it’s time to break out a data migration. Running migrations over and over with different data or comparing lots of queries before and after migrating production data is tedious and error-prone, so let’s write a throw-away test for this migration. You can save this as spec/migration_spec.rb:
require 'spec_helper' require Dir.glob(Rails.root.join("db", "migrate", "*_set_published_posts_for_existing_users.rb")).first describe SetPublishedPostsForExistingUsers do it "counts only published posts" do user = FactoryGirl.create(:user) FactoryGirl.create_list(:post, 3, :user => user, :published => true) reset_cache_and_run_migration user.reload.published_posts_count.should == 3 end def reset_cache_and_run_migration User.update_all("published_posts = 0") SetPublishedPostsForExistingUsers.new.up end endAdd an empty migration, and the test fails because the user is reporting no published posts. We can get this test passing with a simple migration:
class SetActivatedFlagForExistingUsers < ActiveRecord::Migration def up connection.update(<<-SQL) UPDATE users SET published_posts_count = ( SELECT COUNT(*) FROM posts ) SQL end def down # No problem end endNext up, we need to make sure it’s only counting published posts:
it "counts only published posts" do user = FactoryGirl.create(:user) FactoryGirl.create_list(:post, 3, :user => user, :published => true) FactoryGirl.create(:post, :user => user, :published => false) reset_cache_and_run_migration user.reload.published_posts_count.should == 3 endThat will fail because the migration counts the published posts, ending up with a total of four. We can fix that easily:
def up connection.update(<<-SQL) UPDATE users SET published_posts_count = ( SELECT COUNT(*) FROM posts WHERE posts.published = true ) SQL endNext up, we need to make sure each user only counts their own posts, so we add a post for a different user:
it "counts only published posts" do user = FactoryGirl.create(:user) FactoryGirl.create_list(:post, 3, :user => user, :published => true) FactoryGirl.create(:post, :user => user, :published => false) other_user = FactoryGirl.create(:user) FactoryGirl.create(:post, :user => other_user, :published => true) reset_cache_and_run_migration user.reload.published_posts_count.should == 3 endThe test fails again with a count of four, since it picked up the other user’s post. Getting this test to pass leads to our final migration:
def up connection.update(<<-SQL) UPDATE users SET published_posts_count = ( SELECT COUNT(*) FROM posts WHERE posts.published = true AND posts.user_id = users.id ) SQL endAt this point, I just delete the spec. Since migrations should never be edited after they run, there’s little reason to test for regressions. Inevitably the schema will change, which will mean the spec no longer applies.
The spec provides no value after the migration is committed, but I still find writing specs like these well worth the time. It’s easier for me to think like I’m used to, by writing tests first, and it makes me confident that the migration actually covers the cases it’s supposed to.
If you are using Spork 1.0rc in your Rails project and wondering why your controllers etc are not reloading, it's because this functionality has been extracted to the spork-rails plugin gem. Remove the spork reference from your Gem file and add 'spork-rails' instead. spork-rails will include spork 1.0rc as a dependency. This follows the convention for other gems such as rspec-rails and factory_girl_rails. Note spork-rails follows the versioning of minor Rails versions. For example, the current version is 3.2.0, compatible with Rails 3.2.x down to 3.0.0.