Recent notes

RSS feed
June 8, 2009 - (>= v2.2.1)
5 thanks

This is ON by default in :has_many

When defining a has_many relationship this behaviour is on by default. See has_many documentation, look for the :validate flag.

June 6, 2009
9 thanks

add index with :quiet=>true option for indices that are possibly already added

# Allows you to specify indices to add in a migration that will only be created if they do not # already exist, or to remove indices only if they already exist with :quiet=>true module ActiveRecord::ConnectionAdapters::SchemaStatements

def add_index_with_quiet(table_name, column_names, options = {})
  quiet = options.delete(:quiet)
  add_index_without_quiet table_name, column_names, options
rescue
  raise unless quiet and $!.message =~ /^Mysql::Error: Duplicate key name/i
  puts "Failed to create index #{table_name} #{column_names.inspect} #{options.inspect}"
end
alias_method_chain :add_index, :quiet

def remove_index_with_quiet(table_name, column_names, options = {})
  quiet = options.delete(:quiet)
  raise "no options allowed for remove_index, except quiet with this hack #{__FILE__}:#{__LINE__}" unless options.empty?
  remove_index_without_quiet table_name, column_names
rescue
  raise unless quiet and $!.message =~ /^Mysql::Error: Can't DROP/i
  puts "Failed to drop index #{table_name} #{column_names.inspect}"
end
alias_method_chain :remove_index, :quiet

end

June 4, 2009
2 thanks

A typical usage for a mock

You want to use a mock when you’re testing a behaviour of one of your methods that interacts with some outside world service (eg. an FTP server).

it "should login to ftp server" do
  ftp = mock('Ftp server', :null_object => true)
  Net::FTP.should_receive(:new).and_return(ftp)
  ftp.should_receive(:login).with('username', 'password')
  some_obj.connect
end

def connect
  session = Net::FTP.new('server.com')
  session.login('username', 'password')
  session.close
end
June 4, 2009
5 thanks

A catch-all format

If you’d like to specify a respond_to only for 1 or a few formats and render something else for all other formats, eg: (action.rss returns a feed but action.html or action.js should just render 404), use format.all:

respond_to do |format|
  format.rss { render_rss }
  format.all { render_404 }
end

Rails will render an empty string for all formats that don’t specify a response explicitly.

June 4, 2009
2 thanks

example

Ruby style

Dir[File.join(RAILS_ROOT, 'vendor', 'plugins', '*')]

Rails style

Dir[Rails.root.join('vendor', 'plugins', '*')]
June 4, 2009
1 thank

Security hole in 2.3.2

This method has a security hole in Rails 2.3.2. See http://weblog.rubyonrails.org/2009/6/3/security-problem-with-authenticate_with_http_digest for explanation.

Rails 2.3.3 should fix the problem.

June 3, 2009
9 thanks

ActiveRecord::RecordNotSaved can be triggered by accidental false return values in callbacks

You may have this exception raised if any of the defined callbacks such as ActiveRecord::Base#before_save or ActiveRecord::Base#before_create return false.

This can happen accidentally. For example:

class MyModel < ActiveRecord::Base
  before_save :assign_default_foo

protected
  def assign_default_foo
    self.foo = false
  end
end

Since assign_default_foo leaves a false value on the stack, the model will not be saved. A way around this is to simply leave nil or an empty return instead:

class MyModel < ActiveRecord::Base
  before_save :assign_default_foo

protected
  def assign_default_foo
    self.foo = false
    nil
  end
end
June 3, 2009
0 thanks

multi scope to sql

validates_uniqueness_of :name, :scope => [:big_category_id, :small_category_id]

SELECT * FROM schedules WHERE (products.name = 'xxxx' AND products.big_category_id= 1 AND products.small_category_id = 1) LIMIT 1
June 2, 2009 - (>= v2.2.1)
1 thank

Do not create an [ ] method

I created a helper method to access some meta data using

def [](name)
  # do stuff
end

This breaks ActiveRecord behaviors. all belongs_to relations were broken

eg.

class Image
  belongs_to :album
end

i = Image.find :first
i.album_id # 1
i.album # nil

Album.find 1 # works

If you experience this behavior, you probably created a method that breaks the default systematics (like I did with the [ ] method)

June 1, 2009
1 thank

Shared examples

Use it together with share_examples_for like this:

share_examples_for "a shape" do
  it "should have a color" do
    # ...
  end

  it "should have a center point" do
    # ...
  end
end

describe "a circle" do
  it_should_behave_like "a shape"

  it "should be round" do
    # ...
  end
end
June 1, 2009 - (>= v2.2.1)
2 thanks

Further To: Memoize will not cache singleton methods

er…it will:

Code example

class PersonType < ActiveRecord::Base
  class << self
    # Add the mixin here:
    extend ActiveSupport::Memoizable
    def mister
      find_by_name('Mister')
    end
    memoize :mister
  end
end
June 1, 2009
0 thanks

Typical stub! usage

Typically you would call

my_object.stub!(:updated_at).and_return(time_object)
June 1, 2009
2 thanks

Make sure your action names don't step on any toes.

In my experience, if you ever have a controller action named “process”, your controller will cease to function, as there is both a class and instance method called process in ActionController::Base.

There are undoubtedly other action names that will cause conflicts, but this one is particular I’ve run into a number of times.

May 31, 2009
2 thanks

You can call several times

You can call it several times, like:

class Comment < ActiveRecord::Base
  validate :must_be_friends
  validate :must_be_awesome
  ...

or with several arguments:

class Comment < ActiveRecord::Base
  validate :must_be_friends, :must_be_awesome
  ...
May 27, 2009
0 thanks

Potentially slow operation

Remember that checking for a value is a potentially slow operation (all the elements might be iterated) as oposed to querying a key (e.g. with has_key?), which is supposed to be fast in a Hash.

May 27, 2009 - (>= v1_8_6_287)
3 thanks

map_with_index

If you want to access the element index when using map, you can do it with enum_for:

(1..6).enum_for(:each_with_index).map { |v, i| "index: #{i} value: #{v}" }
#=> ["index: 0 value: 1", "index: 1 value: 2", "index: 2 value: 3", "index: 3 value: 4", "index: 4 value: 5", "index: 5 value: 6"]
May 26, 2009
1 thank

Potentially slow operation

Remember that checking for a value is a potentially slow operation (all the elements might be iterated) as oposed to querying a key (e.g. with has_key?), which is supposed to be fast in a Hash.

May 22, 2009
0 thanks

Alternative Way to Handle

This plugin may also help solve the problem from the model side.

http://github.com/rxcfc/multi_assignment_sanity
May 22, 2009 - (<= v2.1.0)
1 thank

Moved

In 2.2 and greater this has moved to ActiveSupport::Dependencies::Loadable#unloadable

May 20, 2009
0 thanks

Symbol Keys Only

While OpenStruct#new is rather indifferent to the kind of keys submitted, marshal_load requires Symbol keys only. Use of a string can cause difficulty.

To fix:

marshal_load(hash.inject({ }) { |h, (k,v)| h[k.to_sym] = v; h })

As a note, Rails has the Hash#symbolize_keys method that can be used in place.

May 19, 2009
0 thanks

Method functions like Hash#merge!

This method functions a lot like Hash#merge! only with a different name.

f = OpenStruct.new
# => #<OpenStruct>
f.marshal_load({:foo => 'bar'})
# => #<OpenStruct foo="bar">
f.foo
# => "bar"
May 19, 2009
2 thanks

Like JavaScript Object

For those familiar with JavaScript naked Objects, this is very similar.

May 19, 2009 - (>= v2.2.1)
2 thanks

How to set request parameters

On previous versions of TestRequest it was possible to set the request_parameters on the new action. This option is now gone, but it’s still possible to set the parameters after initialization.

Code example

request = ActionController::TestRequest.new
request.env["action_controller.request.request_parameters"] = { :foo => '42', :bar => '24' } 
May 15, 2009
0 thanks

script/generate can take table name

As far as I can tell script/generate will happily take the plural table name, at least in Rails 2.3.

May 13, 2009
3 thanks

Equivalent to Array#reject!

This method is functionally identical to Array#reject!

May 12, 2009
2 thanks

form_authenticity_token

Instead of disabling the CSRF check you can pass the authenticity_token field in your forms, eg:

<%= hidden_field_tag :authenticity_token, form_authenticity_token -%>
May 8, 2009
2 thanks

Using gmail SMTP server to send mail

If you’re running Rails >= 2.2.1 [RC2] and Ruby 1.8.7, you don’t need plugin below. Ruby 1.8.7 supports SMTP TLS and Rails 2.2.1 ships with an option to enable it if you’re running Ruby 1.8.7.

All You need to do is:

ActionMailer::Base.smtp_settings = {
  :enable_starttls_auto => true
}
May 7, 2009
0 thanks

RESTful actions

REST adds many constraints. It restricts your controllers to seven actions. Normally this is okay, but sometimes you need to add your own custom actions.

http://railscasts.com/episodes/35-custom-rest-actions

May 7, 2009 - (>= v2.2.1)
1 thank

Question

Can someone add some more information to this?