Recent notes
RSS feeddatabase exceptions will still be raised
Note that save() only returns false on validation errors (when valid? returns false). If other errors occur at the database level, like a database deadlock or trying to insert null into a column that doesn’t allow it, that will still raise an exception.
Testing Net:HTTP connections
You can use this excellent library to stub Net:HTTP connections in your automatic tests:
Naming fragment cache
One of the common ways of using fragment caching is to cache content that’s shared across the site (eg. left navigation, menus, widgets etc.) that looks and works the same regardless of the name of the action or controller calling it. In such cases it’s very easy to just use named fragment caching eg.:
<% cache('left_nav') do -%> <%= display_left_nav -%> <% end -%>
Use :path_prefix for the namespace
Resources are added after the :path_prefix. However if you use a :path_prefix on a resource, it overrides the namespace path instead of appending to it (as I think it should).
Here is what I wrote to create a versioned API access path.
map.namespace :api3, :path_prefix=>"/api/v3" do |api| api.resources :posts api.resources :comments, :path_prefix=>"/api/v3/post/:post_id" end
This will create routes like
path: /api/v3/posts/1 named_route: api3_post() controller=>"api3/posts"
Prevent transactional fixtures for a specific test class
If you want to prevent a specific group of tests from being run inside a transaction, just define inside your test class the methods teardown_fixtures and setup_fixtures with empty bodies.
Prevent transactional fixtures for a specific suite
If you want to prevent a specific group of tests from being run inside a transaction, just define inside your test class the methods teardown_fixtures and setup_fixtures with empty bodies.
Looking for "to the power of"?
If you’re trying to calculate 2 to the power of 2, the ^ method is not what you want. Try ** instead.
2^2 #=> 0 2^8 #=> 10 2**2 #=> 4 2**8 #=> 256
How using Array methods
It’s not possible to use Array methods with a scope because it’s not an Array but an ActiveRecord::NamedScope::Scope :
this
Article.promotion.sum(&:price)
doesn’t run.
But you can use the to_a method to transform the ActiveRecord::NamedScope::Scope to an Array :
Article.promotion.to_a.sum(&:price)
Add has_keys? method to Hash class
class Hash
def has_keys?(*_keys) (_keys - self.keys).empty? end
end
h = {1=>‘a’,2=>‘b’}
h.has_keys?(1,2) #-> true
h.has_keys?(1,3) #-> false
You must use the yielded object
A warning note (at least for v2.3.4): if you don’t use the yielded format object, you will get a cryptic error like this:
NoMethodError (You have a nil object when you didn't expect it! The error occurred while evaluating nil.call): app/controllers/comments_controller.rb:11:in `create'
So make sure you use it!
No Layout, other options
While it renders to the same rules as render, you need to specify params.
You’d think this would work:
render_to_string "users/profile", :layout => false
You need to do this instead
render_to_string(:layout => "users/profile", :layout => false)
has_and_belongs_to_many_with_deferred_save
Be aware that has_and_belongs_to_many saves association to join table immediately after assign. It does NOT wait for my_object.save. Hence if save does not get through validations (or fail for any other reason), associated records will still be in the database.
Here is a nice workaround: http://github.com/TylerRick/has_and_belongs_to_many_with_deferred_save
Avoiding the "multiple values for a block parameter" warning
As pointed out below, you can also have optional parameters. But you will get something like “warning: multiple values for a block parameter (0 for 1)” if you omit them.
You can avoid those warnings by passing *args and picking the parameters yourself:
define_method :that_method do |*args|
foo = args[0] || 'my default' # ... end
Now the warning will be gone. Just make sure you fetch your parameters from *args and assign a default value (unless you want them to default to nil).
Be careful about ActiveRecord::Base.include_root_in_json
If you have set ActiveRecord::Base.include_root_in_json = true, then when you do .to_json on an object, the output will begin with the class name rather than just a hash of attributes.
from the rails docs
konata = User.find(1) ActiveRecord::Base.include_root_in_json = true konata.to_json => { "user": {"id": 1, "name": "Konata Izumi", "age": 16, "created_at": "2006/08/01", "awesome": true} }
if you try to pass this output as the argument to from_json, things will blow up.
User.new.from_json(konata.to_json[“user”]) will just pass in the attribute hash and will work.
Also, note that if you’ve use attr_accessible to limit mass assignment, you’ll have problems if you try pass in attributes that are not allowed to be mass assigned.
Changes self
This method changes the object/array the method is called on. For example:
a = ["a", "b", "c"] b = ["x", "y", "z"] a.concat(b) #=> [a", "b", "c", "z", "y", "z"] a #=> [a", "b", "c", "z", "y", "z"]
In this example the object A is modified, the method modifies the object, then returns the new object.
smtp syntax error 555 5.5.2
If You’re seeing a Net::SMTPFatalError (555 5.5.2 Syntax error ...) than You should check the email’s from header ! You probably have brackets while calling the from attribute setter :
Works in Rails < 2.3.3
def signup_notification(recipient) recipients recipient.email_address_with_name subject "New account information" from %("My App" <no-reply@myapp.com>) end
Works in Rails 2.3.5
def signup_notification(recipient) recipients recipient.email_address_with_name subject "New account information" from 'no-reply@myapp.com' # no <> brackets ! end
in Rails 2.3.3 the from email address will get wrapped with angle brackets, thus it must not have them within the address.
Avoid DoubleRenderError
One can not invoke render twice during an action. Thus if You have a complicated rendering logic but at the end would like to render some default content, or just would like to find out whether render has been called during the current action, use performed?. This also works with “empty” renderings such as head.
Rendering After Exception In respond_to() Block
Remember, format blocks set the response’s content type. This can present problems when handling errors.
class MediaController rescue_from ActionController::MissingFile do |e| # User's browser probably wont display this # Content-Type is application/x-shockwave-flash render :file => File.join(Rails.public_path, '404.html'), :status => 404 end # show details or stream video def show @media = Media.find params[:id] respond_to do |format| format.html format.flv { send_file @media.path, :disposition => 'inline' } end end end
For these situations you must set :content_type when calling render:
render :file => File.join(Rails.public_path, '404.html'), :status => 404, :content_type => 'text/html'
Dynamic exists? methods
There are no dynamic exists? methods analogous to dynamic finders, which means that while you can do this:
Person.find_by_name('David')
you can’t do this:
Person.exists_by_name('David') # DOES NOT WORK
nor this:
Person.exists_by_name?('David') # DOES NOT WORK
However, you can simulate this with dynamic scope:
Person.scoped_by_name('David').exists?
You’ll have to admit that this is so much better than the plain old method:
Person.exists?(:name => "David")
nil Argument Raises An I18n::ArgumentError
You might want to do this:
module ActionView module Helpers module TranslationHelper def localize(*args) #Avoid I18n::ArgumentError for nil values I18n.localize(*args) unless args.first.nil? end # l() still points at old definition alias l localize end end
end
Mode Flags
RDONLY, TRUNC, etc… are defined in the File::Constants module which is include'd by IO and File.
IO.open fd, IO::RDONLY File.open path, File::RDONLY
Though as pointed out above, they are interchangeable.
Errors Raised
Non IO errors (IOError) are contained in the Errno module. They are the same as those given in open(2), see:
http://www.kernel.org/doc/man-pages/online/pages/man2/open.2.html#ERRORS
Common Errors
-
Errno::ENOENT: No such file or directory
-
Errno::EACCES: Permission denied
-
Errno::EEXIST: File exists (i.e. IO::EXCL | IO::CREAT)
Does not work with polymorphic relations
If you have polymorphic relations, e.g.:
class Bookmark < ActiveRecord::Base belongs_to :thing, :polymorphic => true belongs_to :owner, :polymorphic => true end
and you want to ensure that a thing can bookmarked by an owner at most once, you can’t do this:
validates_uniqueness_of :thing, :scope => :owner
Instead, you must use the real column names, e.g.:
validates_uniqueness_of :thing_id, :scope => [:thing_type, :owner_id, :owner_type]
Also behaves like File#expand_path
You can also use URI.join to resolve relative and absolute links:
URI.join('http://example.com/', '/example').to_s # => "http://example.com/example" URI.join('http://example.com/example', 'test').to_s # => "http://example.com/test" URI.join('http://example.com/example/', 'test').to_s # => "http://example.com/example/test" URI.join('http://example.com/example/foo', '../css').to_s # => "http://example.com/css"
Require file from the same folder
If you want to require file from the same folder, the simplest way is
require File.expand_path('../file-to-require', __FILE__)
If your file is /lib/book.rb
File.expand_path('../page', '/lib/book.rb') => '/lib/page.rb'
The :method goes in the :html option
When using a restful form helper and you want to use a method other than POST, remember to put the :method in the :html option.
e.g. To send a DELETE request instead of the usual POST (with a nested resource thrown in for good measure) use:
<% form_for [@post, @comment], :html => { :method => :delete } do |f| -%>
Bad example
Note that it would be better to avoid the alias_method line in the example and just call super.
:autosave => false vs. :autosave => nil
The documentation above mentions that :autosave => true always saves the association and that it’s “off” by default. What it doesn’t mention what they mean by “off”.
-
:autosave => nil (the default “off” behavior) will still autosave the association if it has changed or is a new record.
-
:autosave => false seems to prevent autosaving of the association, even if it has changed.
I’ve found :autosave => false to be useful behavior when trying to prevent cyclical dependency loops; there are likely other useful use cases out there.
Careful with this method.
Despite the name and description, it will actually update any changed fields on the model rather than just the desired attribute.
def update_attribute(name, value) send(name.to_s + '=', value) save(false) end
See? Use update_all and pass in the model ID as a condition, instead.


