Ruby

Anonymizing user, company, and location data using Faker

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) end

Faker’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) end

To 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 ) end

Faker 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_s

Complete code available at this Gist.

Categories: Feed Aggregator

Episode #248 - February 21, 2012

Ruby5 - Tue, 02/21/2012 - 09:10

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).

Categories: Feed Aggregator

Bracket Expansion

Let’s say you want to update capybara and capybara-webkit. You’d normally type this:

gem update capybara capybara-webkit

But 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.

Categories: Feed Aggregator

#326 ActiveAttr

RailsCasts - Tue, 02/21/2012 - 00:00
ActiveAttr provides what Active Model left out. If you need to create a table-less model with features similar to Active Record, watch this episode.
Categories: Feed Aggregator

Naming the Process

Ruby Quicktips - Mon, 02/20/2012 - 21:00

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:

$PROGRAM_NAME = 'Hello from Rubyland!' puts $0 # This is an alias for the same thing.

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!! end

Execute something like this in your terminal:

ps x | grep Quicktips

This tip was submitted by Jesse Storimer.

Categories: Feed Aggregator

This week in open source

copycopter_client

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_girl

Version 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-webkit

Marching 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).

appraisal

Our 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).

clearance

Despite the lack of a release this week, Dan Croak (croaky) put clearance on Travis CI (3430e88 and 91674c6).

bourbon

Neat 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).

diesel

Infrastructural 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).

paperclip

It 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).

Categories: Feed Aggregator

Episode #247 - Februry 17th, 2012

Ruby5 - Fri, 02/17/2012 - 13:33

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.

Categories: Feed Aggregator

Derive #inject for a better understanding

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 end

Computing the product of the list is simple, too:

class EmptyList def product 1 end end class ConsList def product @first * @rest.sum end end

There’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 end

Now 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) end

Join me next time when I talk about monoids closed over the category of endofunctors!

Categories: Feed Aggregator

The Rhythm Method

The Rhythm Method:

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.

Read more on Trajectory’s blog, Mission Control.

Categories: Feed Aggregator

How we ended up organizing a Ruby conference

Andrzej on Software - Thu, 02/16/2012 - 16:24

It started with a Ruby User Group in Wrocław 

It all started with the DRUG meetups. DRUG is a local Ruby user group in Wrocław. As the natural WRUG name was taken by our friends from Warsaw, we have decided to go with D as Dolny Slask, our region in Poland. That's how the awesome name was chosen :)

We gathered together for more than 2 years now. At the start there were about 10 people coming every month. Now it's closer to 20.

The interesting fact about our meetup is that we almost always have like 5-6 talks submitted. Compared to meetups which end up with 1 talk that's quite a difference.

We like to call DRUG a 'conference every month'.

We love sharing opinions and discussions, so we started inviting people from other cities.
We've had guests from Krakow, Silesia, Kopenhagen, Cologne and many other places, we've visited Silesia, Poznan, Trojmiasto, Krakow.

Apart from DRUG meetups there are also DRUG dinners, events at which we just drink beer and discuss, no presentations.

There are also regular DRUG hackathons during which we develop quite a lot of interesting libraries. Bbq and Exceptioner are the ones we're most proud of.

Every day, during our work we like to discuss recent Ruby stuff in the #drug.pl irc channel (freenode).

At some point it was getting quite clear where it's all going to.

We want to organize a conference!

Once the idea came up about a year ago, I don't think there was any discussion if we want to do it. The focus was on "how". Everyone was very excited and the core organizing team set up very quickly.

At first, we decided on the name, date and the venue.

We did a lot of research on what was good/bad on other conferences like Euruko, RuPy, RubyConf etc.

The spirit.

The decision needed to be made if we want to be similar to other conference or shall we go another route.

At some point it was clear that the spirit of our DRUG meetups should shape up the conference. We want it to be about discussions as much as possible. We want it to be about how to make the Ruby world even better than it is.

The idea of fights came up pretty quickly and we're very happy that we kept insisting on it. That's the main conference idea - let's confront different ideas on stage. Let's make it a major part of our conference.

I'm happy to announce the main fights of our conference:

Fight 1 - Rails and OOP

This is all about the recent OOP movements in the Rails world. There are quite a few problems that people focus on and quite a few proposed solutions. We want to cover topics like:

Persistence and domain logic separation
DCI
Backend/frontend separation.
Objects on Rails
TDD
@unclebob ideas - Rails is not your app.

I'm really excited about this "fight". I'm going to blog about this fight more, so stay tuned.


Fight 2 - JRuby vs Rubinius


Which one is better?
Which has the better "support"?
We invited people from both worlds, so the discussion will be of good quality.



Fight 3 - Testing

Shall we keep loving/hating Cucumber?
What about the new tools, like bbq?
Object oriented acceptance testing?
Stubbing or mocking?
TDD - does it make sense?



Agenda and speakers

We didn't just want to invite random famous names from the community. We were focusing on people that fit well with the spirit of our conference. Every talk was carefully chosen. The choice was very difficult as we've had many talks submitted.

What we ended up with is the best Ruby conference agenda I have ever seen. Really.

There's a mission in this conference. We have strong opinions on how some of the Ruby/Rails issues need to be solved. We chosen speakers that are known of their quality and of their strong opinions. We have invited people known of their passion.

Let's have a quick look at some of them:

Apotonick is famous for his REST passion and monolithic apps hate. We share many of his opinions and he is a perfect fit for our conference (also for the parties in the evenings :) ).

Avdi Grimm is the author of the "Objects on Rails" book. This topic makes an important part of our conference.

Steve Klabnik knows a lot about REST and creating API, we're really excited to have him speak on this topic.

The idea of the real DataMapper library that comes with the DataMapper 2 sounds really cool to us and we have Piotr Solnic, its author talking about it.

We have Drogus (Piotr Sarnacki), the Rails commiter, the author of Rails engines.

We believe in distributed apps as the solution to monolithic problems with typical Rails apps. That's why we invited the author of 0MQ -  Martin Sústrik. There's also Florian Gilcher talking about "the fear of processes". Krzysztof Kowalik is going to talk about his lessons learnt from the world of distributed apps.

An important track of our conference is the "frontend apps" track. We have Roy Tomeij speaking about creating reusable frontends with CoffeeScript, sass etc.

We have only one talk about testing, but it will be delivered by Michał Czyż, a developer whom I consider an expert in the topic of acceptance testing. I'm looking forward to his talk.

There's also an original talk planned by Michał Taszycki, "the programmer workout".

There's more to it, so just look at the official agenda.

Don't forget that we have an open space planned, so more talk ideas may come up later :)

Do you want to be part of it?

It's going to be a historical event. You don't want to miss it. 5 years from now people will mention the wroc_love.rb 2012 as the breaking moment for the Ruby/Rails community. Watch it live :)

Although the conference didn't start yet, we already know that the wroc_love.rb 2013 is going to happen as well!

For now, let's focus on this year event. It's only 4 weeks from now, March 10-11.

Make sure you have the ticket, book the hotel and travel. Invite your friends.

Check out the conference website.

It's a community-organized conference. Non-profit. Be part of this community.

Let's make it awesome. Thanks!

BTW, Wrocław is one of the nicest cities in the world, ask anyone who has been here.
Categories: Feed Aggregator

Run a command every time you change directories in zsh

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 } current

This will write the current directory to a hidden file in $HOME; opening a new terminal will automatically cd to that directory.

Categories: Feed Aggregator

Making class methods private

Ruby Quicktips - Wed, 02/15/2012 - 21:00

This does not work:

class Foo private def self.bar end end

Foo.bar will be public.
To make it private, you can use Module#private_class_method:

class Foo def self.bar end private_class_method :bar end

…or define it differently:

class Foo class << self private def bar end end end

This tip was submitted by two-bit-fool.

Categories: Feed Aggregator

Trajectory doesn't have an icebox

Trajectory doesn't have an icebox:

Mission Control:

The icebox is a place where stories go to die. It’s typically used to hold two kinds of stories:

  • Features that need more discussion or planning before they can be started
  • Features that are currently out of scope or very low priority

Read the full post on the Trajectory blog, Mission Control.

Categories: Feed Aggregator

Wildcards in Rails redirects

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-ads

When the user clicks them, they’ll be redirected to:

/?utm_source=email /?utm_source=twitter /?utm_source=search-ads /?utm_source=blog-ads

The 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.

Categories: Feed Aggregator

Is Ruby interpreted or compiled?

Pat Shaughnessy - Tue, 02/14/2012 - 16:00
Both JRuby and Rubinius can compile your
Ruby code into machine language!

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…

Categories: Feed Aggregator

Episode #246 - February 14, 2012

Ruby5 - Tue, 02/14/2012 - 07:54

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.

Categories: Feed Aggregator

Clear your development logs automatically when they are too large

Ruby Quicktips - Mon, 02/13/2012 - 21:00

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 end

This tip was submitted by pahanix.

Categories: Feed Aggregator

How to apply what you've learned from TDD to writing data migrations

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 end

If 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 => false

You 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 end

Add 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 end

Next 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 end

That 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 end

Next 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 end

The 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 end

At 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.

Categories: Feed Aggregator

#324 Passing Data to JavaScript

RailsCasts - Mon, 02/13/2012 - 00:00
There are a variety of ways to pass variables from a Rails application to JavaScript. Here I show three techniques: a script tag, a data attribute, and the Gon gem.
Categories: Feed Aggregator

Heads up: Use spork-rails if you want to use spork 1.0rc in your Rails project

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.

Categories: Feed Aggregator

Pages

Subscribe to SoftOver aggregator - Feed Aggregator