Notes posted to Ruby on Rails

RSS feed
March 21, 2011 - (>= v3.0.0)
0 thanks
March 16, 2011 - (<= v2.3.8)
0 thanks
March 15, 2011
0 thanks

Don't cache it!

Don’t store a connection in a variable, because another thread might try to use it when it’s already checked back in into the connection pool. See: ActiveRecord::ConnectionAdapters::ConnectionPool

connection = ActiveRecord::Base.connection

threads = (1..100).map do
  Thread.new do
    begin
      10.times do
        connection.execute("SELECT SLEEP(1)")  # WRONG
        ActiveRecord::Base.connection.execute("SELECT SLEEP(1)")  # CORRECT
      end
      puts "success"
    rescue => e
      puts e.message
    end
  end
end

threads.each(&:join)
March 14, 2011
0 thanks

formating date

I18n.l Time.now, :format => “%e %B”

http://snippets.dzone.com/posts/show/2255

March 14, 2011
1 thank

Looking for method "l" and "t"

translate # Lookup text translations localize # Localize Date and Time objects to local formats

These have the aliases #t and #l

look at ActionView::Helpers::TranslationHelper

March 8, 2011 - (>= v2.3.8)
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 7, 2011 - (>= v3.0.0)
1 thank

:method => :delete, etc.

If you’re upgrading to Rails 3 you’ll need to make sure you include rails.js (which is in public/javascripts when you rails new someproject) You’ll need to include it after prototype. And you’ll need to have a 1.7 version of prototype.

When you do a

link_to "Delete", @some_obj, :method => "delete", :confirm => "Are you sure?"

Rails 3 will generate

<a href="some_obj/id" data-confirm="Are you sure?" data-method="delete">Delete</a>

rails.js will creates observers that convert that into a form.

Be aware that this probably won’t work as a link from inside a form (since forms in forms isn’t valid).

March 3, 2011 - (>= v3.0.0)
0 thanks

TimeZone in ActiveSupport

This seems to return ActiveSupport::TimeZone and not ::TimeZone as of v.3.0.0 and later.

March 3, 2011
8 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])
March 2, 2011 - (>= v3.0.0)
1 thank

you need use raw

in rails3

select_tag “people”, raw(“<option>David</option>”)

March 1, 2011 - (<= v3.0.0)
2 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 23, 2011 - (>= v3.0.0)
1 thank

Works with scoped too

It’s also available to use after scope chain too, like in any other AR action, for example:

User.where('age > 69').delete_all
February 22, 2011
7 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 17, 2011
2 thanks

You can call it with an { :on => ~~~ } as the last argument

For example:

validate :must_be_friends, :on => :create
February 15, 2011 - (v3.0.0)
0 thanks

No type cast to Float

In Rails 3 the returned value will be type cast to the column’s type and not Float. So when calculating average on a column the column’s type need to be float, the result will be truncated otherwise.

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
February 9, 2011 - (<= v2.3.8)
0 thanks

some gotchas

Works

named_scope :public, :conditions => "public = true"

Works

PUBLIC_CONDITIONS = "public = true"
named_scope :public, :conditions => SomeModel::PUBLIC_CONDITIONS

Works

named_scope :public, lamba { {:conditions => SomeModel.public_conditions} }
def self.public_conditions
  "public = true"
end

Doesn’t work

named_scope :public, :conditions => SomeModel.public_conditions
def self.public_conditions
  "public = true"
end
February 7, 2011
0 thanks

onchange attribute on a hidden field is useless

In the third example there is no sense to set onchange event since it will never happen…

February 7, 2011 - (v1.0.0 - v2.3.8)
0 thanks

If on Rails 3

If you’re on Rails 3, you should look into

http://apidock.com/rails/ActiveRecord/Relation/update_all
February 5, 2011 - (<= v2.3.8)
0 thanks

update_all (and delete_all) don't play nicely with default_scope

If you have

class Topic < ActiveRecord::Base
  default_scope :conditions => "forums.preferences > 1", :include => [:forum]
end

and you do a

Topic.update_all(...)

it’ll fail with

Mysql::Error: Unknown column 'forums.preferences' in 'where clause'

The work around for this is:

Topic.send(:with_exclusive_scope) { Topic.update_all(...) }

You can monkey patch this using this code (and requiring it in environment.rb or else where)

module ActiveRecordMixins
  class ActiveRecord::Base
    def self.update_all!(*args)
      self.send(:with_exclusive_scope) { self.update_all(*args) }
    end
    def self.delete_all!(*args)
      self.send(:with_exclusive_scope) { self.delete_all(*args) }
    end
  end
end
end

Then just you update_all! or delete_all! when it has a default scope.

January 27, 2011
1 thank

Dont reject! on the yielded batch

If you remove any values from the batch, the while loop in find_in_batches breaks even if there are additional batches:

People.count # => 3000

People.find_in_batches do |peeps|
  peeps.reject!(&:bad?)
  # ... more operations on peeps
  puts 'Tick'
end

Running the above code, you’ll only see Tick once. Rather use:

People.find_in_batches do |peeps|
  peeps = peeps.reject(&:bad?)
  # ... more operations on peeps
  puts 'Tick'
end

You should see Tick outputted 3 times

January 26, 2011 - (>= v3.0.0)
2 thanks

Use this for validatating nested forms

When you create a nested form, and want the main object to validate all nested models, you should make all the nested models dirty or validations will not run upon them.

class Order < ActiveRecord::Base
  has_many :order_lines
  accepts_nested_attributes_for :order_lines

  before_validation :mark_order_lines_as_changed

  private
  def mark_order_lines_as_changed
    order_lines.each(&:updated_at_will_change!)
  end
end
January 24, 2011
0 thanks

Does not respond to ajax call

I inherited some code that used form_remote_tag. send_file and send_data did not work.

Changing from from_remote_tag to form_tag and all worked as expected.

January 24, 2011
0 thanks

you probably want:

Rails.env

or possibly:

ActionController::TestRequest.new (which has a demo of how to set env vars on a controller test)

January 21, 2011 - (<= v2.3.8)
0 thanks

Doesn't work for associations.

This method relies on #blank? to determine if the attribute is valid.

When you call #blank? on an ActiveRecord object, it returns true as long as there are no changes to the object.

So you can validate the base attribute (i.e.: product_id), but you’ll have no guarantee that it points to a valid record without your own validator.

January 18, 2011
2 thanks

Common AJAX options

See the documentation for link_to_remote to see the common AJAX options, like :before and :completed.

January 18, 2011
0 thanks

Grouping

Person.sum(:age, :group => “sex”) # =>[[“male”,2500],[“female”,2200]]

January 18, 2011
2 thanks

Grouping

Person.sum(:age, :group => “sex”) # =>[[“male”,2500],[“female”,2200]]