Edge Rider: Power tools for ActiveRecord scopes

In our continued quest to extract proven code snippets from makandropedia into tested and upgradable gems, we have released Edge Rider.

Edge Rider was created with two intents:

  1. Provides a number of utility methods to facilitate hardcore work with scopes.
  2. Provide a stable API for working with scopes across multiple versions of Rails, since Rails has a tradition of breaking details of its scope API every other release.

The gem bundles multiple patches and initializers we've been using for hard...

Traverse an ActiveRecord relation along an association

The Edge Rider gem gives your relations a method #traverse_association which
returns a new relation by "pivoting" around a named association.

Say we have a Post model and each Post belongs to an author:

class Post < ActiveRecord::Base
  belongs_to :author
end

To turn a relation of posts into a relation of its authors:

posts = Post.where(:archived => false)
authors = posts.traverse_association(:author)

You can traverse multiple associations in a single call.
E....

The many gotchas of Ruby class variables

TLDR: Ruby class variables (@@foo) are dangerous in many ways. You should avoid them at all cost. See bottom of this card for alternatives.

Class variables are shared between a class hierarchy

When you declare a class variable, it is shared between this and all descending (inheriting) classes. This is rarely what you want.

Class variables are bound at compile-time

Like unqualified constants, class variables are bound to your current scope *whe...

Prevent double clicks on link_to_remote (simple case)

This works well in the simplified case, when your link disappears after it was clicked.

Let link_to_remote behave as „disabled“ after the first click. Use the :before hook to replace the orignal link with a link that does nothing but looks like the original link:

:ruby
  label = "do_something"
  dummy_link = link_to(label)
  other_attributes_hash = { :url => ..., :method => ..., ... }
  
  disable_link_option = { :before => "$('your_link_selector').html('#{escape_javascript(dummy_link)}'" } # jquery

= link_to_remote(label, other_att...

Regex: Be careful when trying to match the start and/or end of a text

Ruby has two different ways to match the start and the end of a text:

  • ^ (Start of line) and $ (End of line)
  • \A (Start of string) and \z (End of string)

Most often you want to use \A and \z.

Here is a short example in which we want to validate the content type of a file attachment. Normally we would not expect content_type_1 to be a valid content type with the used regular expression image\/(jpeg|png). But as ^ and $ will match lines, it matches both content_type_1 and content_type_2. Using \A and \z will wo...

What The Rails Security Issue Means For Your Startup

January has been a very bad month for Ruby on Rails developers, with two high-severity security bugs permitting remote code execution found in the framework and a separate-but-related compromise on rubygems.org, a community resource which virtually all Ruby on Rails developers sit downstream of. Many startups use Ruby on Rails. Other startups don’t but, like the Rails community, may one day find themselves asking What Do We Do When Apocalyptically Bad Things Happen On Our Framework of Choice? I thought I’d explain that for the general c...

How to update a single gem conservatively

The problem

Calling bundle update GEMNAME will update a lot more gems than you think. E.g. when you do this:

bundle update cucumber-rails

... you might think this will only update cucumber-rails. But it actually updates cucumber-rails and all of its dependencies. This will explode in your face when one of these dependencies release a new version with breaking API changes. Which is all the time.

In the example above updating cucumber-rails will give you Capybara 2.0 (because capybara is a dependency of `cucumber-rail...

Running "bundle update" without arguments might break your application

Calling bundle update (without arguments) updates all your gems at once. Given that many gems don't care about stable APIs, this might break your application in a million ways.

To stay sane, update your gems using the applicable way below:

Projects in active development

Update the entire bundle regularily (e.g. once a week). This ensures that your libraries are up-to-date while it's easy to spot major version bumps which may break the app.

Projects that have not been updated in a while

  1. [Update a single gem conservatively](htt...

RVM: Get rid of your system Ruby

If you worked with a system Ruby before switching to RVM, this system Ruby will be in your way when you switch between projects with/without RVM.

It's hard to get rid of your system Ruby entirely, but you can tell RVM to just use a given Ruby by default, e.g.:

rvm --default use 1.8.7

You need to re-open existing terminals for the changes to take effect.

Note that this will not actually remove the ruby package from your system, it just isn't used anymore.

Ruby: How to ensure a Tempfile's extension

If you use Tempfile and pass your own filename containing an extension, it will just be consumed by the Tempfile's filename:

>> Tempfile.new('foobar.xlsx').path
=> "/tmp/foobar.xlsx20130115-19153-4ykpwm-0"

If you want to keep the file extension, pass filename and extension as an array:

>> Tempfile.new([ 'foobar', '.xlsx' ]).path
=> "/tmp/foobar20130115-19153-1xhbncb-0.xlsx"

How to get the hostname of the current machine in Rails or a Ruby script

Use Socket.gethostname. So for a machine whose hostname is "happycat", it will look like this:

>> Socket.gethostname
=> "happycat"

That should work right away for your Rails application. For plain Ruby, you first need to do:

require 'socket'

If you don't want to use Socket for some reason, you can still just use the hostname command, at least on non-Windows machines. Keep in mind that you need to remove trailing white space from the result of the system call.

>> `hostname`
=> "happycat\n"
>> `hostname`.stri...

Fix error: undefined method `desc' for #<Foo::Rake::Taskx1234>

Upgrade the offending gem. If you cannot or don't want to upgrade, lock rake to 0.8.7.

will_paginate can paginate plain Ruby arrays

While you are probably using will_paginate to paginate ActiveRecord scopes, it can actually paginate plain Ruby arrays. The resulting arrayish object will have the same methods as a paginated scope, e.g. #total_entries. This means you can render pagination controls with the same code that works with paginated scopes.

To enable this, add an initializer config/initializers/array_paginate.rb:

require 'will_paginate/array'

You can now say:

> numbers = (1..1000).to_a
> page = numbers....

Rails 4 Countdown to 2013 | The Remarkable Labs Blog

With the impending release of Ruby on Rails 4, it looks like a lot of developers will be updating their web applications in the coming new year.

To help with this transition, over the next 31 days, we are going to be releasing a series of blog posts going over everything you will need to know about Rails 4 for an effortless upgrade.

Error installing ffi gem

Do this before you install the gem:

 sudo apt-get install libffi-dev

King of Nothing, the DCI paradigm is a scam

I’ve worked on huge applications in Ruby and Rails before. I very much want to believe in DCI, but I’m having a hard time accepting the promises of Clean Ruby when it seems like the work on this paradigm is half-done. If it weren’t so oversold and hyped, I think I’d be more patient, but right now I’m just frustrated and confused.

randym/axlsx · GitHub

Axlsx is an incredible gem to generate "Office Open XML" spreadsheet files (XLSX). Does not break on large spreadsheets and supports a ton of features like graphs.

API looks mature and existing code is easy to migrate when coming from the spreadsheet gem.
The documentation of some methods is a bit out of date, but you'll find your way around the gem's code.

No support for reading files, however. :( If you want to open XLSX spreadsheets (for example to confirm your output in tests), you can use [roo](h...

RSpec: Defining helper methods for an example group

You can define methods in any example group using Ruby's def keyword or define_method method:

describe "example" do
  def sum(a, b)
    a + b
  end

  it "has access to methods defined in its group" do
    expect(sum(3, 4)).to be(7)
  end
end

The helper method is also available to groups nested within that group. The helper method is not available to parent or sibling groups.

Global helpers

To define helpers for all specs (or all specs of a type), [define it in a module](https://rspec.info/features/3-12/rspec-core/help...

Everything you ever wanted to know about constant lookup in Ruby

If you ever wondered why a constant wasn't defined or wasn't available where you expected it to be, this article will help.

Also see Ruby constant lookup: The good, the bad and the ugly.

How to package a non-Ruby file into a gem

Great solution in a GitHub issue.

Cronjobs: "Craken" is dead, long live "Whenever"

Our old solution for cronjobs, the "craken" plugin, is no longer maintained and does not work on Rails 3.2+.

We will instead use the whenever gem.

"Whenever" works just like "craken", by putting your rake tasks into the server's cron table. Everything seems to work just like we need it.

Installation for new projects

  1. Add "whenever" to your Gemfile:

     group :deploy do
       gem 'whenever', require: false
     end
    
  2. Add it to your config/deploy.rb:
    ...

navy gem: Hide empty navigation bars

navy 0.5.1+ gives empty navigation containers a CSS class .navy-empty which you can hide via

.navy-navigation
  &.navy-empty
    display: none

SearchableTrait is now a gem: Dusen

For two years we've been using SearchableTrait which gives models the ability to process Googlesque queries like this:

Contact.search('a mix of words "and phrases" and qualified:fields')

This trait used to be a huge blob of code without tests and documentation, so I made a gem out of it. Check out https://github.com/makandra/dusen for code, tests, and a huge README.

You should use the Dusen gem and delete SearchableTrait in all future projects.

Note that the syntax to define query proc...

byebug / ruby-debug: Find out current debugger position

So you are debugging like a boss and lost track of where you actually are in your code? No problem:

  • Calling "l=" will show you the current file and line. That's a lower-case L and an equals sign.
  • "where" (or "backtrace") will give you the debugger call stack, including current file and line as well. It can be quite long.