Consul 0.9 lets you optimize records checks

Consul 0.9 comes with many new features to optimize powers that only check access to a given record. e.g. Power.current.post?(Post.last). See below for details.

Powers that only check a given object

Sometimes it is not convenient to define powers as a collection. Sometimes you only want to store a method that
checks whether a given object is accessible.

To do so, simply define a power that ends in a question mark:

class Power
  ...

  power :upd...

How to tell ActiveRecord how to preload associations (either JOINs or separate queries)

Remember why preloading associations "randomly" uses joined tables or multiple queries?

If you don't like the cleverness of this behavior, you can explicitely tell ActiveRecord how to preload associations with either JOINs or separate queries.

This card gives an overview of the different options to preload associations, but

__Whic...

Common mistakes when storing file uploads with Rails

1. Saving files to a directory that is not shared between deploys or servers

If you save your uploads to a made up directory like "RAILS_ROOT/uploads", this directory goes away after every deploy (since every release gets a new). Also this directory is not shared between multiple application servers, so your uploads are randomly saved to one local filesystem or another. Fixing this afterwards is a lot of fun.

Only two folders are, by default, shared between our application servers and deployments: "RAILS_ROOT/storage" and `"RAILS...

Upgrading Rails 2 from 2.3.8 through 2.3.18 to Rails LTS

This card shows how to upgrade a Rails 2 application from Rails 2.3.8 through every single patch level up to 2.3.18, and then, hopefully, Rails LTS.

2.3.8 to 2.3.9

This release has many minor changes and fixes to prepare your application for Rails 3.

Step-by-step upgrade instructions:

  1. Upgrade rails gem
  2. Change your environment.rb so it says RAILS_GEM_VERSION = '2.3.9'
  3. Change your ...

ActiveRecord.select

Active Record's select method allows you to make use of the power of MySQL select statements. On the one hand it allows you to select specific fields.

Post.select("content")

results in the following query:

"SELECT content FROM `posts`"

This means that your models will be initialized with only the content attribute and you will not be able to access any other attribute. In fact trying so would raise an ActiveRecord::MissingAttributeError error.

 Post.select("content").first.title # => ActiveRecord::MissingAttributeErr...

Before you make a merge request: Checklist for common mistakes

Merge requests are often rejected for similar reasons.

To avoid this, before you send a merge request, please confirm that your code ...

Virtus: Coercing boolean attributes

TLDR

Do it like this:

attribute :active, Virtus::Attribute::Boolean

Long story

In Virtus you define attribute with their type like this:

attribute :name, String
attribute :birthday, Date

When defining a boolean attributes, you will probably write it like this:

attribute :active, Boolean

The problem is, there is not actually a Boolean class in Ruby (there's only TrueClass and FalseClass), so use Virtus::Attribute::Boolean instead.

The reason whil...

How to find out which type of Spec you are

When you need to find out in which kind of spec you are during run-time, it's definitely possible. It's a lot easier in RSpec 2+.

For example, consider this global before block where you'd want to run some code for specific specs only:

config.before do
  # stuff
  that_fancy_method
  # more stuff
end

RSpec 2+

If you want to run such a block for a specific type of specs, you can use filters:

config.before do
  # stuff
  # more stuff
end

config.before :type =...

Mac OS: Remove app from Launchpad

Issue this command:

sqlite3 ~/Library/Application\ Support/Dock/*.db "DELETE from apps WHERE title='APP_NAME';" && killall Dock

This tells sqlite3 to remove the app called APP_NAME from the Launchpad database and then kill the process called Dock, thereby restarting it.

Fixing authentication in legacy applications

Authentication is hard: there are many edge cases, and most users (including yourself) usually only go the "happy path" once and never see the edge cases. If you have rolled your own authentication, or been using older authentication solutions, or resorted to HTTP Basic Authentication, this card will tell you what to do to make your application safe.

Any application that stores sensitive data in the browser

That is: cookies, e.g. by offering a login.

  • Ask the admins to [turn on SSL](https://makandracards.com/makandra/1416-integrate-s...

Good real world example for form models / presenters in Rails

We have often felt the pain where our models need to serve too many masters. E.g. we are adding a lot of logic and callbacks for a particular form screen, but then the model becomes a pain in tests, where all those callbacks just get in the way. Or we have different forms for the same model but they need to behave very differently (e.g. admin user form vs. public sign up form).

There are many approaches that promise help. They have many names: DCI, presenters, exhibits, form models, view models, etc.

Unfortunately most of these approaches ...

Pitfall: ActiveRecord callbacks: Method call with multiple conditions

In the following example the method update_offices_people_count won't be called when office_id changes, because it gets overwritten by the second line:

after_save :update_offices_people_count, :if => :office_id_changed? # is overwritten …
after_save :update_offices_people_count, :if => :trashed_changed? # … by this line

Instead write:

after_save :update_offices_people_count, :if => :office_people_count_needs_update?

private

def office_people_count_needs_update?
  office_id_changed? || trashed_changed?
end

Or...

Detect city, country from IP address

  • You can detect city and country from an IP address by using the GeoLite database. This is a flat file you can copy into your project (~ 20 MB).
  • You can access the database using the geoip gem.
  • You need to attribute MaxMind if you are using the data.
  • Accuracy sort of sucks. For most countries 1/3 of addresses cannot be resolved within 40 kilometers, probably because the Inter...

How to fix: "unexpected token" error for JSON.parse

When using the json gem, you might run into this error when using JSON.parse:

>> json = 'foo'.to_json
>> JSON.parse(json)
JSON::ParserError: 757: unexpected token at '"foo"'
	from /.../gems/json-1.7.7/lib/json/common.rb:155:in `parse'
	from /.../gems/json-1.7.7/lib/json/common.rb:155:in `parse'
	from (irb):1

Why?

The error above happens because the JSON you supplied is invalid.

While to_json does work correctly, the result itself is not JSON that can be parsed back, as that s...

How to write complex migrations in Rails

Rails gives you migrations to change your database schema with simple commands like add_column or update.
Unfortunately these commands are simply not expressive enough to handle complex cases.

This card outlines three different techniques you can use to describe nontrivial migrations in Rails / ActiveRecord.

Note that the techniques below should serve you well for tables with many thousand rows. Once your database tables grows to millions of rows, migration performance becomes an iss...

ActiveRecord: Passing an empty array into NOT IN will return no records

Caution when using .where to exclude records from a scope like this:

# Fragile - avoid
User.where("id NOT IN (?)", excluded_ids)

When the exclusion list is empty, you would expect this to return all records. However, this is not what happens:

# Broken example
User.where("id NOT IN (?)", []).to_sql
=>  SELECT `users`.* FROM `users` WHERE (id NOT IN (NULL))

Passing an empty exclusion list returns no records at all! See below for better implementations.

Rails 4+

Use the .not method to let Rails do the logic

`...

Firefox >= 23 will block mixed content when using SSL

Non-SSL contents on SSL pages are blocked by default

Bug 834836 – Turn on pref to block mixed active content

Firefox 18 introduced preferences to block loading contents from non-SSL (http) sites on SSL (https) pages. One of those preferences, security.mixed_content.block_active_content is now enabled by default in order to enhance user security. That means insecure scripts, stylesheets, plug-in contents, inline frames, Web fonts and WebSockets are blocked on secure pages, and a notification is displayed instead. It will not block...

Rails: Overwriting default accessors

All columns of a model's database table are automagically available through accessors on the Active Record object.

When you need to specialize this behavior, you may override the default accessors (using the same name as the attribute) and simply call the original implementation with a modified value. Example:

class Poet < ApplicationRecord

  def name=(value)
    super(value.strip)
  end

end

Note that you can also avoid the original setter and directly read/write from/to the instance's attribute storage. However this is dis...

parallel_tests: Disable parallel run for tagged scenarios

Note: This technique is confusing and slows down your test suite.


Copy the attached code to features/support. This gets you a new Cucumber tag @no_parallel which ensures that the tagged scenario does not run in parallel with other scenarios that are tagged with @no_parallel. Other scenarios not tagged will @no_parallel can still run in parallel with the tagged test. Please read the previous sentence again.

This can help when multiple test processes that access a single resource that is hard to shar...

ApacheBench may return "Failed requests" for successful requests

When you use ab to do some performance benchmarking, you might run into output like this:

Complete requests:      200
Failed requests:        5
   (Connect: 0, Receive: 0, Length: 5, Exceptions: 0)

Note that in our example these "Failed requests" actually never failed.\
For some requests, the application just returned a response with a different content length than the first response. This is indicated by the "Length: 5" bit in the example above.

If you see requests that failed with other kinds of errors, they probably fail...

Rails' Insecure Defaults - Code Climate Blog

Rails’ reputation as a relatively secure Web framework is well deserved. Out-of-the-box, there is protection against many common attacks: cross site scripting (XSS), cross site request forgery (CSRF) and SQL injection. Core members are knowledgeable and genuinely concerned with security.

However, there are places where the default behavior could be more secure. This post explores potential security issues in Rails 3 that are fixed in Rails 4, as well as some that are still risky. I hope this post will help you secure your own apps, as w...

Rails: How to use a n:m association as 1:n association

Sometimes you might want to limit the number of associated records in a has_many association, but cannot add a foreign key to the other model (using belongs_to).

There are many takes on limiting the number of associated records in has_many associations, but none feels smooth.

However, when your...

Comparing Rails' flash hashes will not respect their internal lists of used entries

Rails flashes (FlashHash) track a list of used keys, which is not respected when comparing flash hashes.

This does not concern you under most circumstances.

Basics

When ActionController picks up a flash object, it will call the #sweep method once; that method checks the list of used flash entries and deletes those. All other entries are flagged as used. This means they will be deleted on the next request, but are still be available for rendering during the current request.

Fun facts: When redirecting, this does not happen. Also,...

Don't assign time values to date attributes

Do not pass times to date attributes. Always convert times to dates when your application uses time zones.

Background

A time-zoned Time attribute on a Rails record is converted to UTC using to_s(:db) to be stored, and converted back into the correct time zone when the record is loaded from the database. So when you are not on UTC, time objects will be converted as follows.

>> Time.current
=> Fri, 15 Mar 2013 11:56:03 CET +01:00
>> Time.current.to_s(:db)
=> "2013-03-15 10:56:03" # This is now UTC

Problem

That will...