Model:
###########
class Artist < ActiveRecord::Base
require ‘pp’
def initialize
end
def print
pp self.attributes { |col| col.value}
end
end
Test Case:
###########
require File.dirname(__FILE__) + ‘/../test_helper’class ArtistTest < Test::Unit::TestCase
fixtures :artists
def test_create
new_artist = Artist.new
p “created artist”
new_artist.name = “name for artist”
p new_artist.print
end
end
Here’s the output:
###########
test_create(ArtistTest):
NoMethodError: You have a nil object when you didn’t expect it!
You might have expected an instance of Array.
The error occured while evaluating nil.include?
/usr/local/lib/ruby/gems/1.8/gems/activerecord-1.14.4/lib/active_record/base.rb:1772:in `method_missing’
./artist_test.rb:16:in `test_create’
def initialize
end
- Hank Beaver
h2. It just burns the edge
This is a page dedicated to all the small things that can go wrong and result in the massive uprooting of hair.
I spent a frustrating day finding out that while it’s ok echo variables to the stdout in IRB, the same puts statement will cause the ugliest un-traceable error ever if executed from the browser. I find no hint of error in the logger either. The solution? Never use “puts” anywhere.
- ?
Another solution is to put:
def print_debug(string)
echo string
end
print_debug stringwithin your code elsewhere. Also allows you to have a consistent way to display your debugging strings with some editing to the parameters.
-KittyKate
If you are developing more than one app on the same box, and are switching back and forth, you may mysteriously get situations where nothing loads, but you don’t get errors. Clear the session cookie for the host (0.0.0.0 in most cases) and you will be fine.
If you’re using ActiveRecord for storing your sessions, make sure the sessions table exists, as it not being there can also cause silent failure. If not using AR for sessions, try removing the sess_ files from your temp directory.
has_and_belongs_to_many and InheritanceI had a table called ‘users’ from which I inherited two types of users: Teachers and Students. (Model declaration looks like class Student < User) Obviously, a student has_and_belongs_to_many :teachers, and a teacher has_and_belongs_to_many :students. I had also created the students_teachers table, and could confirm that rows were being added properly. However, teacher.students was returning an empty array. The solution? Explicitly name the ‘users’ table by passing :table_name => 'users' in the has_and_belongs_to_many association.
Given :table_name => 'users' Rails will not look for a table called ‘teachers’ at all. Any reference to objects of type ‘teacher’ are mapped to entries in the ‘user’ table with type = ‘Teacher’. [See SingleTableInheritance ]. If a table ‘teachers’ exists it will be ignored by this model. If it does not exist, no error will be raised. [jjw]
—Hari Seldon?
Can’t make your \ActiveRecord class work? You may have named it something that’s already defined in Ruby or Rails. For a list of names you can’t use:
rubyr config/environments/production -e ‘print Object.constants.sort.join(", ")’
ruby -r config/environment -e ‘print Object.constants.sort.join(", ")’Speical Special Notice
If you’re running rails > 1, the above will not work. use instead:
./script/runner ‘print Object.constants.sort.join(", ")’
—David Salamon
Webrick has more reserved words than Apache or Lighty. For example, Log is not a reserved word in Lighty or Apache, but it is in Webrick. Be sure if you are running Webrick for development and Lighty or Apache for production you understand these differences to help prevent later frustration.
— JeremyDurham
See the full list of ReservedWords which also includes reserved SQL words
—SamStephenson
There are currently two tickets open about this:
Also note that numerous field names have special properties. See the full list of MagicFieldNames.
In Ruby, nil.id is 4. This means that any time you try to take the id of something that’s nil, you get 4. In turn, this can lead to problems in Rails.
For example, let’s say you have a Teacher object, and you believe the Teacher has a Student. So at some point you do:
sid = teacher.student.id
to get the student’s id. But what you’ll get, if Teacher has a student method but this particular teacher doesn’t have a student, is 4 — because teacher.student will give you nil. Since the code won’t fail, you might not realize that somewhere else there’s a bug that is causing the Teacher not to have been assigned a Student.
So be alert for unexpected retrievals of things with id 4!
Note that this will finally be changed in future Ruby versions. For now you can try helping yourself with something like this:
def nil.id() raise(ArgumentError, "You are calling nil.id!") end
(Just put the code into your ApplicationHelper file or somewhere similar.)
Also beware that an empty string evaluates to true, so it will be displayed when you do
<pre>
<% if work.name %>
<h2><%= work.name %>
<% end %>
To check if a string contains nothing, just use blank?. This is a convenience method made for you by Rails on all objects.
<pre>
<% unless work.name.blank? %>
<h2><%= work.name %>
<% end %>
—Julik
Some Rails environments (mod_ruby and FCGI) persist class configurations between requests, so you might shoot yourself in the foot when using class-level attributes when handling actions. It might seem convenient to store something there, but it might be that another user will be interacting with the same class (and his requests will use the same class attribute). Be also aware that class methods that change class state are not reverted between requests, so if you do
<pre>
class MyController < ApplicationController
def some_action
#lets turn off the layout just for this action
MyController.layout = false
end
end
it will actually disable layout for all subsequent requests to this controller on this application instance (Apache process or FCGI handler).
—Julik
Collection of my Rails gotchas here: http://www.ruby-forum.org/bb/viewtopic.php?t=14
To Hari Seldon?: I don’t know why you deleted this before – it looks like a relevant content
— AlexeyVerkhovsky
Alexey, the phpBB install it’s on seems to be insecure.
— MikeSugarbaker
Alexy, the site has been shut down due to security problems – can you paste the 20+ gotchas here?
—DennisSutch
I was trying to associate a user with an issue (for a simple ticket tracker), but every time I did:
issue.users << user
Things would silently fail. The problem turned out to be that the validations were again being checked for the user object (specifically the password_confirmation, which I didn’t have because the record had already been saved) . Adding ‘:on => :create’ to that validation cleared up the problem.
The symptoms of this problem can be seen in the log as:
SQL (0.000609) BEGIN
SQL (0.000540) COMMIT
someobject.save silently failing. If you look at the error attribute of someobject:
logger.debug someobject.errors.to_yaml
users:
– &id002 !ruby/object:User
[…]
errors: !ruby/object:ActiveRecord::Errors
base: *id002
errors:
password_confirmation:
– “can’t be empty”
Better yet, if you’re using LoginGenerator, you should set both the password and password_confirmation to ’’ before saving, and the before_update filter will take care of that validation for you. Setting it to only validate on creation is asking for trouble.
— JoelYoung?
From the trivial-once-you-get-it box:
Q: The application works on several nearly-identical boxes, but on one instead of running the dispatcher it shows the dispatcher source. ExecCGI? is good, all the directory permissions are the same, and dawn is comming soon. rsync claims that all the files in the application directories (except the logs) are as identical as you can get. And the logs aren’t showing anything. What in the heck is the problem?
A: FastCGI? isn’t installed right on that box. Change it’s .htaccess to use .cgi and make sure to fix it after you get some sleep.
RMagick uses stubs to access the lower level C objects, and doesn’t actually know about the memory used by them. Thus, the garbage collector doesn’t get kicked off when it should, and this results in massive memory usage.
The solution is to use RMagick, and when it’s done its thing, insert a call to GC.start to trigger the garbage collection.
There’s chapter and verse on this in the RMagick forums here : http://rubyforge.org/forum/forum.php?thread_id=1374&forum_id=1618, but it’s hidden away a bit. I happpened on it by accident when heading over there to raise a bug report :-)
Anyway, an example:
def self.new()
new_image = super
new_image.created_at = Time.new
new_image.updated_at = Time.new
new_image.full_image_mimetype = 'image/jpeg'
new_image.thumbnail_image_mimetype = 'image/jpeg'
new_image.full_image = Binary.new
new_image.thumbnail_image = Binary.new
blank = Image.new(240,240) {
self.background_color = 'white'
self.format = 'jpeg'
}
new_image.full_image.binary_data = blank.to_blob
blank = Image.new(75,75) {
self.background_color = 'white'
self.format = 'jpeg'
}
new_image.thumbnail_image.binary_data = blank.to_blob
# Done with RMagick, so trigger GC to get rid of those pesky objects
GC.start
return new_image
end
This simple fix, 2 lines to my model, took an app that was regularly gobbling up 250MB+ per instance and requiring hourly cronned restarts back down to the expected 20-30M or so, and stable in memory usage from day to day.
Following the ActionWebService manual , you get to the point where you add the “web_service_scaffold :invoke”, and test in a browser. You are greeted with:
Errno::ENOENT in Backend#invoke
No such file or directory ...
The problem is that the Pathname class makes some assumptions about absolute paths that don’t play well with others, if they’re running on windows. (In my case, my rails root was on drive D:, while my ruby installation was on drive C:, haven’t determined if this matters or not) Here’s a (slightly tested) patch for ruby/lib/ruby/1.8/pathname.rb YMMV
--- ruby/lib/ruby/1.8/pathname.rb 2004-12-12 09:04:31.000000000 -0700
+++ ruby/lib/ruby/1.8/pathname-new.rb 2005-06-09 16:21:30.453125000 -0600
@@ -309,20 +309,29 @@
# No arguments should be given; the old behaviour is *obsoleted*.
#
def realpath(*args)
+ require 'rbconfig'
+
unless args.empty?
warn "The argument for Pathname#realpath is obsoleted."
end
force_absolute = args.fetch(0, true)
- if %r{\A/} =~ @path
- top = '/'
+ is_absolute = %r{\A/}
+ top = '/'
+
+ # Win32 hacks
+ if Config::CONFIG["arch"] =~ %r{cygwin|mingw32|mswin32}i
+ is_absolute = %r{\A[A-Za-z]:/}
+ top = ''
+ end
+
+ if is_absolute =~ @path
unresolved = @path.scan(%r{[^/]+})
elsif force_absolute
# Although POSIX getcwd returns a pathname which contains no symlink,
# 4.4BSD-Lite2 derived getcwd may return the environment variable $PWD
# which may contain a symlink.
# So the return value of Dir.pwd should be examined.
- top = '/'
unresolved = Dir.pwd.scan(%r{[^/]+}) + @path.scan(%r{[^/]+})
else
top = ''
— solo
You’ll also want to be changing around absolute
def absolute?
is_absolute = %r{\A/} =~ @path ? true : false
#added
# Win32 hacks
if Config::CONFIG["arch"] =~ %r{cygwin|mingw32|mswin32}i
is_absolute = %r{\A[A-Za-z]:/}
end
#end added
is_absolute
end
h3. Incorrect id values being generated in :finder_sql
I discovered that any SQL where the value reference #{foo} is used will generate an incorrect value for foo when the SQL appears in double quotes ("). The solution is to use single quotes (’).
See also this message posting .
I found all of my major apps broke when upgrading to Rails 0.13, but simple ones did not. It turned out to be a change in Routes. Routes will now not accept integers in route parameters. If you quote them, your app will work in 0.13.
—Peter Cooper?
IE failed to render effects with the new prototype.js and effects.js on my pages. Safari and Firefox were fine. All attempts to run effects got a “Object does not support this method or property” error. After an hour of playing around, I found that having an element with an id of “options” on the page causes it. Change any elements with an id of “options” to any other name, and it works great.
—Peter Cooper?
<pre>
class PublicController < ApplicationController
before_filter :filter_everyone, :except => 'index'end
class ProtectedController < PublicController
before_filter :filter_everyone
end
I thought ProtectedController#index would yield a blank page because I intended the before_filter in that class to apply to every action. However, since no conditions were provided and it uses the same method as the before_filter in PublicController, it’s stuck with the old conditions. A quick fix is to explicitly provide the desired conditions, as in:
<pre>
class ProtectedController < PublicController
before_filter :filter_everyone, :except => ''
end</pre>
—Matt Walker
_id on the nameGiven:
<pre>class User < ActiveRecord::Base
belongs_to :frobble
end</pre>
Find the bug that causes Rails to burp Frobble expected, got String:
<pre>collection_select(:user, :frobble, @users, :id, :name)</pre>
Hair loss ends when it becomes :frobble_<i>id</i>.
This is probably basic, but Ruby uses elsif, NOT elseif.
I notice the following SQL when pulling out a single record:
<pre>
SELECT * FROM categories WHERE (categories.id = 2) LIMIT 1
</pre>
This is a bug in my eyes. If there were > 1 records with this id, the database column is faulty setup and I would want to know as soon as possible.
As documented
collections returned from an association collection (added by has_many or has_and_belongs_to_many override Enumerable#find in a manner which is incompatible with the original. Consider using its alias Enumerable#detect if you need the original functionality.
You can’t do e.g.
def oos_to_aas! self = self.gsub(“o”, "a") endbut rather
self[0..-1] = self.gsub(“o”, "a")or
replace(gsub(“o”, "a"))as “self” is an object, not a variable. Of course, in the example above, you could simply do
self.gsub!(“o”, "a")…
This code will cause an NilError:
unless @user redirect_to index_url endtitle = "Hello, {#user}!"
The reason is that the controller code does not stop executing at encountering a redirect_to or render. The redirect or render is simply queued until the controller is done. The solution is to either use an else like
unless @user redirect_to index_url elsetitle = "Hello, {#user}!"
end
which seems to be the idiomatic way, or (less elegant, perhaps?) to return from the controller to stop its further execution:
unless @user redirect_to index_url return endtitle = "Hello, {#user}!"
The alternative form
redirect_to index_url and returnlooks a bit cooler.
if you’re doing a redirect_to from a before_filter, you can return false to end execution.
Its in the documentation, but if you are trying to print your web page, be sure to note that the default for stylesheet_link_tag is :media => “screen”. This snafued me. Didn’t notice it until 6 hours later. I was reformatting my screen in a thousand different ways to make everything really simple, only to have NO STYLESHEET for printing. I should have just set :media => “all” or created a separate stylesheet for printing.
If your application features a SOAP API, when running in production mode, your API might break if it recieves requests using the 1999 schema ie:
<?xml version"=>"\"1.0\" encoding=\"UTF-8\"?><SOAP-ENV:Envelope xmlns:xsi=\"http://www.w3.org/1999/XMLSchema-instance\" xmlns:SOAP-ENC=\"http://schemas.xmlsoap.org/soap/encoding/\" xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsd=\"http://www.w3.org/1999/XMLSchema\" SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\"><SOAP-ENV:Body><namesp919:FooBar xmlns:namesp919=\"http://foo.bar.com/api/v2\"><token xsi:type=\"xsd:string\">x
The UR-Type datatype seems to be especially problematic.
Works fine when the requests all use the 2001 schema, and also seems to work fine in modes other than production…
Anyway, our kludge work-around is to inspect each request in a before_filter, and if it matches “www.w3.org/1999” or “ur-type” we do:
load 'xsd/datatypes1999.rb'
and then in an after_filter we do:
load 'xsd/datatypes.rb' unless XSD::Namespace == "http://www.w3.org/2001/XMLSchema"
(XSD::Namespace is changed by loading datatypes1999.rb).
observe_field tags need to be declared AFTER the field that is being observed in the document. Otherwise you get javascript errors
When pluralization rules are added to the environments.rb inflector rules, they don’t hold true for the models within a module
Example:
Inflector.inflections do |inflect|
inflect.uncountable “media”
end
Generate an Admin scaffold for Media
C:\Projects\media_app>ruby script/generate scaffold Admin::Media create app/controllers/admin create app/helpers/admin exists app/views/admin/medias create test/functional/admin dependency model create app/models/ create test/unit/ create test/fixtures/ create app/models/medias.rb create test/unit/medias_test.rb create test/fixtures/medias.yml identical app/views/admin/medias/_form.rhtml create app/views/admin/medias/list.rhtml create app/views/admin/medias/show.rhtml create app/views/admin/medias/new.rhtml create app/views/admin/medias/edit.rhtml create app/controllers/admin/medias_controller.rb create test/functional/admin/medias_controller_test.rb create app/helpers/admin/medias_helper.rb create app/views/layouts/medias.rhtml create public/stylesheets/scaffold.css Loaded suite script/generate Started Finished in 0.0 seconds. 0 tests, 0 assertions, 0 failures, 0 errors
You will notice it does not use media; rather it uses medias
To work around this, add admin::media to the inflection settings:
Inflector.inflections do |inflect| inflect.uncountable "media", “admin::media” end
More info on the issue on my blog
That’s all!
If you try to add a record to a table with a field named ‘User’ you can expect an error like the following:
ActiveRecord::StatementInvalid in UseradminController#createOCIError: ORA-00928: missing SELECT keyword: INSERT INTO gcousers (user, app, role, id) VALUES
RAILS_ROOT: c:/RailsApps/GCO/config/..
Renaming the field to something like ‘Userid’ gets rid of the problem.
Status: 500 Internal Server Error Content-Type: text/html
Application error (Apache)
Change this error message for exceptions thrown outside of an action (like in Dispatcher setups or broken Ruby code) in public/500.html
It is a very bad idea to call a method named process in the controller.
def process
end