Flowdock

Recent good notes

RSS feed
March 18, 2013
3 thanks

Beware - May cause performance issues

A serialized attribute will always be updated during save, even if it was not changed. (A rails 3 commit explains why: http://github.com/rails/rails/issues/8328#issuecomment-10756812)

Guard save calls with a changed? check to prevent issues.

class Product < ActiveRecord::Base
  serialize :product_data
end

bad

product = Product.first
product.save

good

product = Product.first
product.save if product.changed?
August 30, 2012
3 thanks

Usage

In Rails 3.X console:

Rails.application.routes.recognize_path('/my_path')
July 24, 2012
3 thanks

rest of code is in NilClass#try

If you click “Show source” here, you may get confused. The logic for #try is shared between this method and NilClass#try . Both versions are currently implemented in the file activesupport/lib/active_support/core_ext/object/try.rb .

April 26, 2012
4 thanks
April 25, 2012 - (>= v3.1.0)
6 thanks

HTML5 data- attributes using RESTful approach

HTML5 specifies extensible attributes like data-foo=“bar” (or as in Twitter Bootstrap data-toggle=“modal”), which poses two problems for Rails.

First, if you’re using symbol notation in link_to to specify attributes, this fails (dash is not a valid symbol character), so

Invalid!

link_to "Edit", @user, :class => "btn", :data-toggle => "modal"

There are two solutions:

  1. put the symbols in quotes,

  2. use the special :data hash

Solution 1: Quote Symbols

link_to "Edit", @user, :class => "btn", "data-toggle" => "modal"

Solution 2: Use the :data hash

link_to "Edit", @user, :class => "btn", :data => {:toggle => "modal"}

Resulting HTML

<a href="/users/1" class="btn", data-toggle="modal">Edit</a>

The second is minimally documented, but as a hash, can accept multiple values and is perhaps a little cleaner

March 27, 2012
4 thanks

Makes it possible to use a scope through an association

This is a very useful method if you want to to use a scope through an association:

class Book < ActiveRecord::Base
  scope :available, where(:available => true)
end

class Author < ActiveRecord::Base
  has_many :books
  scope :with_available_books, joins(:books).merge(Book.available)
end

# Return all authors with at least one available book:
Author.with_available_books

See http://asciicasts.com/episodes/215-advanced-queries-in-rails-3 for more info.

March 27, 2012
3 thanks

Reorder

If you want to override previously set order (even through default_scope), use reorder() instead.

E.g.

User.order('id ASC').reorder('name DESC')

would ignore ordering by id completely

November 11, 2011
3 thanks

Catching and throwing -- don't!

@wiseleyb and @glosakti, neither of your suggestions are necessary, and both are bad practices.

This test:

test "transactions" do
  assert_raises ZeroDivisionError do
    User.transaction do
      1/0
    end
  end
end

passes just fine on its own, with the transaction rolled back as you’d expect. No need to hack something ugly together.

November 6, 2011 - (>= v3.1.0)
3 thanks

Removed in 3.1.x

This method (and #auto_link_urls) has been removed in Rails 3.1 - other options are out there, such as Rinku, however there is a gem you can use for migration purposes etc, which is rails_autolink: http://rubygems.org/gems/rails_autolink

October 19, 2011 - (>= v3.0.0)
3 thanks

Replaced by :on => :create

From rails 3,

before_validation_on_create 

has been removed and replaced with:

before_validation :foo, :on => :create
October 8, 2011
5 thanks

Undocumented :location option

You can use undocumented :location option to override where respond_to sends if resource is valid, e.g. to redirect to products index page instead of a specific product’s page, use:

respond_with(@product, :location => products_url)  
October 7, 2011
3 thanks

How to submit current url

For example to change some kind of param on select change…

<%= form_tag({}, {:method => :get}) do %>
  <%= select_tag :new_locale, options_for_select(I18n.available_locales, I18n.locale), :onchange => "this.form.submit();" %>
<% end %>
June 4, 2011 - (>= v3.0.0)
4 thanks

finding without default scopes in rails 3

if you want to find without default scopes in rails 3 and with_exclusive_scope is giving you protected method errors in controllers, use unscoped for a similar purpose

May 23, 2011 - (>= v3.0.5)
5 thanks

Change to the way the block is handled

At least in 3.0.5, some of the previous examples no longer work: ActionView seems to quietly ignore Array content.

If you were using code of the form

content_tag(:li, nil, :class => 'someClass') {
  arr.collect { |x|
    content_tag(:ul, x)
  }
}

it now needs to look like

content_tag(:li, nil, :class => 'someClass') {
  arr.reduce('') { |c, x|
    c << content_tag(:ul, x)
  }.html_safe
}
March 25, 2011
4 thanks

How to specify :only_path when non-hash options

When passing in an object, as opposed to a hash, you can’t do this because url_for accepts one argument:

url_for(post, :only_path => true)

Instead, do this:

polymorphic_url(object, :routing_type => :path)
March 8, 2011 - (v2.3.8 - v3.0.5)
3 thanks

Dont use _delete

Most blog articles about accepts_nested_attributes_for, including the one from @mattsa and @annaswims, tell you to add a

'_delete' => 1

when you want a deletion checkbox, hidden attribute, etc.

But this stopped being true a while ago. This is just a “Watch Out!” Make sure you use

'_destroy' => 1

instead.

March 3, 2011
7 thanks

Using namespaces

If you are using a namespace in your routes.rb, for example:

namespace :admin do
  resources :products
end

then you can:

url_for([:admin, @product])

and:

url_for([:edit, :admin, @product])
February 22, 2011
5 thanks

Passing arguments to block

To pass arguments to block being captured, just list them as capture method params. I.e.

def export(exportable, export_klass, options={}, &block)
  result = ""
  #...
  if block_given?
    result += capture(my_custom_var_i_want_to_pass_to_block, &block)
  end
  result
end

Then simply…

 <%= export(@a, @b) do |my_custom_var| %>
  <% if my_custom_var.nil? %>
    My custom var is nil!!!
  <% end %>
<% end %>
February 21, 2011 - (>= v3.0.0)
8 thanks

case-insensitive uniqueness

For case-insensitive uniqueness:

validate :username, :uniqueness => {:case_sensitive => false}
February 10, 2011 - (<= v2.3.8)
3 thanks

Undocumented callbacks

Not sure why this isn’t documented… there are callbacks for before/after_add and before/after_remove. Example

has_many :things, :after_add => :set_things, :after_remove => :remove_things

def set_things(thing)
  ...
end
def remove_things(thing)
  ...
end
January 11, 2011
5 thanks

Disable STI

I had to add “self.inheritance_column” as opposed to simply “inheritance_column” to get this to work.

Code example

class MyModel < ActiveRecord::Base
  # disable STI
  self.inheritance_column = :_type_disabled
end
December 10, 2010 - (>= v3.0.0)
3 thanks

complex conditions

If you need add complex conditions you can use this:

Model.where(:foo => 'bar').where(:attr => 1).update_all("author = 'David'")
December 8, 2010 - (>= v3.0.0)
3 thanks

helpers using options for select

You can now add html options to select options by creating a container with items like the following:

Code Example

['display','value',:class => 'option_class']

This will produce:

Code Example

<option value="value" class="option_class">display</option>
November 9, 2010
8 thanks

NOT Equivalent to Array#reject!

@tadman is wrong. There is a difference and, trust me, it can bite:

1.9.2 > [1,2,3,4].delete_if {|x| x > 10}
 => [1, 2, 3, 4] 
1.9.2 > [1,2,3,4].reject! {|x| x > 10}
 => nil 

That is, if reject! hasn’t rejected anything, it returns nil.

October 26, 2010
3 thanks

Polymorphic has_many within inherited class gotcha

Given I have following classes

class User < ActiveRecord::Base
end

class ::User::Agent < ::User
 has_many :leads,  :as => :creator
end

I would expect, that running

User::Agent.first.leads

will result in following query

SELECT "leads".* FROM "leads" WHERE ("leads".creator_id = 6 AND "leads".creator_type = 'User::Agent')

however it results in

SELECT "leads".* FROM "leads" WHERE ("leads".creator_id = 6 AND "leads".creator_type = 'User')

Possible solutions:

  • Make User class use STI - polymorphic relations will then retrieve correct class from :type field (however in my situation it was not an option)

  • If You do never instantiate User class itself, mark it as abstract

class User < ActiveRecord::Base
 self.abstract_class = true
end
  • If You do instantiate User class, as last resort You can overwrite base_class for User::Agent

class ::User::Agent < ::User
 has_many :leads,  :as => :creator

 def self.base_class
  self
 end
end
  • If none of above is an option and You do not care that You will lose some of relation’s features, You can always

class User::Agent < ::User
 has_many :leads,
          :as => :creator,
          :finder_sql => %q(SELECT "leads".* FROM "leads" WHERE ("leads".creator_id = #{id} AND "leads".creator_type = 'User::Agent'))
end
October 20, 2010
6 thanks

use raw() instead

Don’t use this method unless you’re sure your string isn’t nil. Instead use the raw() method, which wont raise an exception on nil.

October 16, 2010 - (>= v3.0.0)
10 thanks

needs to be paired with respond_to

Needs to be paired with respond_to at the top of your class.

class MyController < ApplicationController
  respond_to :js, :html