Flowdock

Notes posted to Ruby on Rails

RSS feed
March 17, 2010
0 thanks

Validations

out of the box touch will run with validations

March 16, 2010 - (>= v2.2.1)
0 thanks

config/environments/production.rb

old

ActionController::AbstractRequest.relative_url_root= "/exampleapp"

new

config.action_controller.relative_url_root= "/exampleapp"
March 13, 2010
3 thanks

Can be used with has_many associations

You can also use this to validate that a has_many association has a specified number of records on the other end:

has_many :members

validates_length_of :members, :minimum => 1
March 11, 2010
1 thank

Skips validations and callbacks

The method skips validations and callbacks. That is why it should be used with caution.

Code example

person.toggle :active
March 11, 2010
3 thanks

Available statuses

All the available statuses (extracted from SYMBOL_TO_STATUS_CODE hash) in a slightly more readable form:

:continue                        => 100
:switching_protocols             => 101
:processing                      => 102
:ok                              => 200
:created                         => 201
:accepted                        => 202
:non_authoritative_information   => 203
:no_content                      => 204
:reset_content                   => 205
:partial_content                 => 206
:multi_status                    => 207
:im_used                         => 226
:multiple_choices                => 300
:moved_permanently               => 301
:found                           => 302
:see_other                       => 303
:not_modified                    => 304
:use_proxy                       => 305
:temporary_redirect              => 307
:bad_request                     => 400
:unauthorized                    => 401
:payment_required                => 402
:forbidden                       => 403
:not_found                       => 404
:method_not_allowed              => 405
:not_acceptable                  => 406
:proxy_authentication_required   => 407
:request_timeout                 => 408
:conflict                        => 409
:gone                            => 410
:length_required                 => 411
:precondition_failed             => 412
:request_entity_too_large        => 413
:request_uri_too_long            => 414
:unsupported_media_type          => 415
:requested_range_not_satisfiable => 416
:expectation_failed              => 417
:unprocessable_entity            => 422
:locked                          => 423
:failed_dependency               => 424
:upgrade_required                => 426
:internal_server_error           => 500
:not_implemented                 => 501
:bad_gateway                     => 502
:service_unavailable             => 503
:gateway_timeout                 => 504
:http_version_not_supported      => 505
:insufficient_storage            => 507
:not_extended                    => 510
March 11, 2010
2 thanks

Good way to see what went wrong

Use the message parameter like that:

assert_response :success, @response.body

If this fails (the response isn’t a success), it will display the response body along with the failure message, thus allowing you to quickly find out what went wrong. If the response is e.g. 500, there will probably be some exception stacktrace displayed in the body. And so on.

March 10, 2010
0 thanks

Specify your own template

You can specify you own template this way:

def notice
  ...
  @template = "some_other_name.html.erb"
end
March 4, 2010
1 thank

AASM named scopes

If you are using the aasm plugin/gem, this will generate all named scopes for your various states.

Code example

Class Article <  ActiveRecord::Base

  include AASM

  aasm_initial_state :created

  aasm_state :published
  aasm_state :unpublished
  aasm_state :deleted
  aasm_state :created

  aasm_event :publish do
    transitions :to => :published, :from => [:created]
  end

  aasm_event :unpublish do
    transitions :to => :unpublished, :from => [:created, :published]
  end

  aasm_event :delete do
    transitions :to => :deleted, :from => [:published, :unpublished]
  end

  aasm_states.each { |s| named_scope s, :conditions => { :state => s.to_s } }  

end
March 4, 2010
3 thanks

Re: Caveat when using dynamic layouts

Since there’s no way to edit posts on here, I need to correct myself and say that what I posted before doesn’t work, since you can’t specify layout multiple times:

class OrdersController < BaseController
  layout :determine_layout, :only => :new
  layout "public", :except => :new
  # ...
end

So don’t do that. The only way to ensure that the other actions get the default theme is to drop :only/:except and do the conditions yourself:

class OrdersController < BaseController
  layout :determine_layout

private
  def determine_layout
    %w(new).include?(action_name) ? "some_layout" : "public"
  end
end

All this to say, beware of :only/:except – they aren’t as useful as you think they are.

February 27, 2010
4 thanks

Caveat when using dynamic layouts

Worth noting that if you have a controller which inherits from another controller which has a layout, and in this child controller you’re determining the layout at runtime using a method for specific actions, the other actions you are excluding will not inherit the layout from the parent controller.

For example, if you’ve got this

class BaseController < ApplicationController
  layout "public"
end
class OrdersController < BaseController
  layout :determine_layout, :only => :new
  # index, show, new, create, edit, update, destroy ...
end

then OrdersController#index, #show, and #edit won’t get the “public” layout – in fact they won’t get a layout at all. So you’ll need to do this instead:

class OrdersController < BaseController
  layout :determine_layout, :only => :new
  layout "public", :except => :new
  # ...
end
February 26, 2010
3 thanks

default_scope on create

If you specify :conditions in your default_scope in form of a Hash, they will also be applied as default values for newly created objects. Example:

class Article
  default_scope :conditions => {:published => true}
end

Article.new.published? # => true

However:

class Article
  default_scope :conditions => 'published = 1'
end

Article.new.published? # => false
February 25, 2010
2 thanks

configuration no longer in environment.rb

configure session store in config/initializers/session_store.rb

February 25, 2010
1 thank

Saving other objects inside before_save

Don’t call .save or .update_attribute on other objects inside before_save callback.

Saving other objects inside of before_save callback results in flushing changed hash and the original object is not updated.

UPDATE observed sometimes, still investigating

February 25, 2010
1 thank

Redirect...

See ActiveRecord::ConnectionAdapters::TableDefinition#column for details of the options you can use.

February 25, 2010
2 thanks

Possible gotcha

This method returns a Pathname object which handles paths starting with a / as absolute (starting from the root of the filesystem). Compare:

>> Rails.root
=> #<Pathname:/some/path/to/project>
>> Rails.root + "file"
=> #<Pathname:/some/path/to/project/file>
>> Rails.root + "/file"
=> #<Pathname:/file>
>> Rails.root.join "file"
=> #<Pathname:/some/path/to/project/file>
>> Rails.root.join "/file"
=> #<Pathname:/file>
February 25, 2010
0 thanks

See documentation for the class method

Since Rails version 2, this instance method no longer exists.

You may be looking for its namesake class method, ActiveRecord::Base.method_missing

February 23, 2010
3 thanks

Easy workaround for missing :through option

Note that belongs_to does not support :through option like has_many (although IMHO it would make sense in some cases), but you can easily simulate it with delegate.

For example:

class Person < ActiveRecord::Base
  belongs_to :team
  ...
end
class Task < ActiveRecord::Base
  belongs_to :person
  delegate :team, :to => :person
end

There is of course more ways to do it, but this seems to be the easiest to me.

February 23, 2010
0 thanks

note: the example format regex is too lenient

The example regex for RFC 2822 email is too lenient. Sure it’s just an example, but it wound up in our code and we just had to fix it to match the RFC.

The regex as given allows any non-@ non-whitespace characters. But the RFC only allows these characters in mailbox names

alpha digit - ! \ # $ % & ' * + \ / = ? ^ _ ` { | } ~ ] +

and . is only allowed between atoms of 1 or more of the above.

Here’s the corrected regex:

:with => /\A([-a-z0-9!\#$%&'*+\/=?^_`{|}~]+\.)*[-a-z0-9!\#$%&'*+\/=?^_`{|}~]+@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i
February 16, 2010 - (>= v2.1.0)
3 thanks

Extract the aggregated scoping options

If you want to get the aggregated scoping options of a chain of named scopes use ActiveRecord::Base.current_scoped_methods

It works in the fashion of:

Shirt.red.medium.alphabetical.current_scoped_methods
# ==>
{
  :create => {}, 
  :find => {
    :conditions => {:color => 'red', :size => 'medium'}, 
    :order => 'shirts.name ASC'
  } 
}
February 12, 2010
1 thank

re: Options

@ramanavel - The options are dependent on the cache store that you’re using. You’ll need to have a look at what the cache store you’re using allows.

e.g. MemCacheStore allows the use of time criteria based :expires_in, most of the cache stores don’t.

http://guides.rubyonrails.org/caching_with_rails.html might provide a little more information.

February 11, 2010
4 thanks

reload equivalent for models

The reset_column_information method provides a similar function for the model itself. Most useful during migrations.

February 9, 2010
0 thanks

Options

What are all the options here please?…

February 5, 2010
2 thanks

the :order parameter is not sanitized

The :order parameter is not sanitized, so doing something like Person.find( :first , :order => params[:order] ) could get you in trouble.

February 5, 2010
1 thank

An alternate way to have a string ID as a primary key

You can disable automatically created primary key and add it to manually with mysql:

The migration file:

def self.up

  create_table( :my_special_table, :id => false ) do |t|
    t.string :id, :limit => 5, :null => :no
  end

  execute "ALTER TABLE my_special_table ADD PRIMARY KEY (id)"

end

Then in a before_save filter you can generate the primary key for yourself.

Use a transaction and be aware of uniqueness!

February 4, 2010 - (>= v2.1.0)
0 thanks

All dates in the database are stored in UTC and all dates in Ruby are in a local timezone

With the timezone support introduced in Rails 2.1 the idea is that all dates in the database are stored in UTC and all dates in Ruby are in a local timezone.

Time.zone.now == Time.now # => false

as Peter Marklund lights up this in his blog:

http://marklunds.com/articles/one/402

“They will only be converted to UTC for you if they are ActiveSupport::TimeWithZone objects, not if they are Time objects. This means that you are fine if you use Time.zone.now, 1.days.ago, or Time.parse(”2008-12-23“).utc, but not if you use Time.now or Time.parse(”2008-12-23“)”

January 30, 2010
3 thanks

Paying attention to query parameters

Standard action caching ignores query parameters, which means you’d get the same results for a URL with and without query parameters if it was action cached. You can make it pay attention to them by using a custom cache path like so:

caches_action :my_action, :cache_path => Proc.new { |c| c.params }

Or, maybe you want some of the query parameters, but not all to factor into different versions of that action’s cache:

:cache_path => Proc.new { |c| c.params.delete_if { |k,v| k.starts_with?('utm_') } }

Beware of things like pagination if you use expires_in to expire the cache, as pages could get out of sync.

January 29, 2010
1 thank

Passing html options (Ruby hash parameters)

When you have two default hash parameters at the end of a function call, you need to use it as the following:

options = { :include_blank => true, :default => @my_object.my_method }

date_select :my_object, :my_method, options, :class => 'my_css_class'

You can try it for yourself on this example:

def test_funct a = {}, b = {}
  puts "a: #{a.inspect}"
  puts "b: #{b.inspect}"
end

test_funct :x => 'x', :y => 'y'  # all the parameters are collected for the hash a
January 27, 2010
1 thank

Alternative hostname generation method

Instead of using a random number to generate the hostname for the single asset, I prefer using source.hash.modulo, so that a given file is always served from the same host. This makes the content more cacheable by browsers and proxies.

ActionController::Base.asset_host = Proc.new { |source|
  "http://assets#{ source.hash.modulo(9) }.example.com"
}

I didn’t benchmark how long it takes, but String#hash should be reasonably fast.

January 26, 2010 - (>= v2.3.2)
1 thank

is now a subclass of Hash that preserves order (or _is_ a Hash if running Ruby 1.9 or greater)

You might not realize it preserves order because it delegates inspect to its super-class, Hash, which doesn’t preserve order. But you will see that order is preserved if you iterate or use the keys or values methods:

>> names = ['Amy Irving', 'Jane Doe', 'John Doe', 'John Updike', 'Susan Anthony']
>> ordered = names.group_by { |name| name.split.first }
=> #<OrderedHash {"John"=>["John Doe", "John Updike"], "Amy"=>["Amy Irving"], "Susan"=>["Susan Anthony"], "Jane"=>["Jane Doe"]}>

>> ordered.keys
=> ["Amy", "Jane", "John", "Susan"]

>> ordered.each { |first, full| puts first; full.each { |name| puts "  "+name } }
Amy
  Amy Irving
Jane
  Jane Doe
John
  John Doe
  John Updike
Susan
  Susan Anthony