Why are validations failing in my tests even without any messages?!
If you have done a
config.gem 'mocha'
in environment.rb or test.rb try removing that and adding
require 'mocha'
to the bottom of your test_helper.rb file.
The other day I created a mailer to send a notification when my Request model created a new instance. so I did a "rails generate mailer Mailer request" and that's when I started getting the error:
ArgumentError: wrong number of arguments (0 for 1)
I spent a great deal of time googling and trying to figure out what I had done wrong then finally on an inkling I tried changing the method from "request" to "new_request" and voila, problem solved.
Moral of the story: if you get this error, maybe you are unintentionally overriding an existing method and you should rename your mailer method.
I found myself wanting to set an attr_accessor to handle passing a date to my model in a form_for tag with the f.datetime_select helper. So this is what I had:
Model:
attr_accessor :my_time
View:
<%= f.datetime_select :my_time %>
Unfortunately when I submit my form I get this:
1 error(s) on assignment of multiparameter attributes
Well it turns out that this is actually a Rails bug a ticket for which has been submitted. In the meantime how do we make this work? The only solution I could find that was remotely attractive was to make use of composed_of as a replacement for attr_accessor. so...
Model:
composed_of :my_time,
:class_name => 'Time',
:mapping => %w(Time to_s),
:constructor => Proc.new{ |item| item },
:converter => Proc.new{ |item| item }
I know almost nothing about the composed_of method so you should probably do your own reading on it, but what I do know is that it creates both a reader and writer for the given instance variable, and more importantly, the setter accepts multiparameter attributes. How I chose the options:
- class_name: the name of our expected class. In this case, "Time"
- mapping: the first argument is the class and the second argument seems to work with any method that an instance of the class responds to. I chose "to_s"
- constructor: Not really sure how this is supposed to work. Seems to be called when the @my_time is nil.
- converter: Not really sure how this is supposed to work. Seems to be called when from my_time=, but doesn't seem to be applied with mass assignment.
One problem I ran into with this solution was that times were getting set in UTC instead of the environment's time zone. So unfortunately we cannot use my_time directly, but instead need to convert it to the proper time zone:
Time.zone.parse(stop_and_set.to_s(:number))
The other day I ran into this issue when trying to deploy with Capistrano to my staging server running Ubuntu 6.06. I had just updated my Ruby version from 1.8.4 to 1.8.7 with RVM. While the solution was difficult to find, it was quite simple, I just didn't know which libraries I was looking for:
sudo apt-get install curl
sudo apt-get install libcurl3
sudo apt-get install libcurl3-gnutls
sudo apt-get install libcurl3-gnutls-dev
Problem solved.
I recently inherited a project and my first task I set myself was to see that all the tests passed. I immediately ran into problems:
psql:/Users/gabeodess/Sites/my_app/db/development_structure.sql:1: ERROR: relation "schema_migrations" does not exist
and
1) Error:
test_the_truth(BankAccountTest):
ActiveRecord::StatementInvalid: PGError: ERROR: relation "bank_accounts" does not exist
: DELETE FROM "bank_accounts"
Something was seriously amiss because that failed test was a simple "assert(true)". Furthermore I had no idea where /db/development_structure.sql was coming from.
So my first move was to delete /db/development_structure.sql to see what happened so I did and ran "rake test" again and found that /db/development_structure.sql was automatically recreated.
Move two was google. I quickly found that development_structure.sql is an alternate format for your schema.rb file and is configured in environment.rb with
config.active_record.schema_format = :sql
So I opened environment.rb and sure enough there was that line of code. I removed it and now my test run as they should.
Banged my head against the wall for a while on this one. Turns out that "du" does not include files that have been deleted but not erased.
So I used a tool that does find deleted files:
pound@loadbalancer:~$ sudo lsof -ns | grep -i delete
nginx 27838 root 2u REG 8,1 14212308992 1984094 /usr/local/nginx/logs/error.log (deleted)
nginx 27838 root 3u REG 8,1 14212308992 1984094 /usr/local/nginx/logs/error.log (deleted)
nginx 27838 root 4u REG 8,1 3321648825 1984843 /usr/local/nginx/logs/access.log (deleted)
nginx 27839 nobody 2u REG 8,1 14212308992 1984094 /usr/local/nginx/logs/error.log (deleted)
nginx 27839 nobody 3u REG 8,1 14212308992 1984094 /usr/local/nginx/logs/error.log (deleted)
nginx 27839 nobody 4u REG 8,1 3321648825 1984843 /usr/local/nginx/logs/access.log (deleted)
And there they were. Giant deleted nginx log files soaking up my disk space. In my case restarting nginx cleaned those out.
Since I always seem to forget the details on how this all works, I have decided to document it here. This example uses Rails 2.3.8.
In this example we will be dealing with 3 models: projects, associated_tasks, and tasks. As you can probably guess:
class Project < ActiveRecord::Base do
has_many :associated_tasks
has_many :tasks, :through => :associated_tasks
end
What we would like to do in this example is when we create a new project we would like to see a list of the available tasks, check off the ones that we want to associate with our project, and also assign a billing rate to the associated task that will be created. Naturally we would like our code to persist to the edit form. So here we go.
The first step is to allow nested attributes. So in our Project model:
class Project < ActiveRecord::Base do
has_many :associated_tasks
has_many :tasks, :through => :associated_tasks
accepts_nested_attributes_for(:associated_tasks)
end
Now that our model accepts nested attributes, we can go into the form and add our nested attributes
<%- f.fields_for :associated_tasks do |form| -%>
<%= render '/associated_tasks/fields', :f => form %>
<%- end -%>
What this block will do is loop through all of the associated tasks in f.object.associated_tasks and print out the fields defined in app/views/associated_tasks/fields for each of them. Of course nothing will be printed out now because our @project does not have any associated tasks, so let's go to the controller and add some:
def new
@project = Project.new
@tasks = Task.all
@tasks.each do |task|
@project.associated_tasks.build(:task => task)
end
end
And in our edit action:
def edit
@project = Project.find(params[:id])
@tasks = Task.all
@tasks.each do |task|
@project.associated_tasks.build(:task => task) unless @project.associated_tasks.include?(task)
end
end
Now when you reload your form you should see fields being printed out for each task. If you submit your form now all of the associated tasks will be created. We don't want that. What we would like to do is be able to check off which tasks we want and only save those. To accomplish this we will use the built in "_destroy" attribute for associated models. We will check each associated task to see if its _destroy attribute is "1" and if it is we will not save it.
First we need to add the check box to app/views/associated_tasks/_fields.html.erb. In this case, we want the field checked by default when the associated_task is not a new record, and unchecked otherwise. We want the checked value to be "0" and the unchecked value to be "1".
<%= f.hidden_field :project_id %>
<%= f.hidden_field :task_id %>
<%= f.check_box :_destroy, {:checked => !f.object.new_record?}, 0, 1 %>
<%= f.object.task.name %>,
<%= f.label :billing_rate, "Billing Rate" %>
$<%= f.text_field :billing_rate, :size => 3 %>/hr
Next, in Project we need to reject all associated tasks where "_destroy" equals "1"
class Project < ActiveRecord::Base do
has_many :associated_tasks
has_many :tasks, :through => :associated_tasks
accepts_nested_attributes_for(
:associated_tasks,
:reject_if => proc{ |obj| obj.delete('_destroy') == '1' }
)
end
And that's it! Since we used the _destroy attribute as our conditions, Rails automatically removes associated tasks when they are unchecked.
In upgrading to ruby 1.9.1 and Rails 3, my first error was caused by not having the sqlite3-ruby gem installed. Trying to install it with the standard gem command I got the following error:
$gem install sqlite3-ruby
Building native extensions. This could take a while...
ERROR: Error installing sqlite3-ruby:
ERROR: Failed to build gem native extension.
/.../.rvm/rubies/ruby-1.9.1-p378/bin/ruby extconf.rb
checking for sqlite3.h... yes
checking for sqlite3_libversion_number() in -lsqlite3... yes
checking for rb_proc_arity()... yes
checking for sqlite3_initialize()... no
sqlite3-ruby only supports sqlite3 versions 3.6.16+, please upgrade!
*** extconf.rb failed ***
Could not create Makefile due to some reason, probably lack of
necessary libraries and/or headers. Check the mkmf.log file for more
details. You may need configuration options.
Provided configuration options:
--with-opt-dir
--without-opt-dir
--with-opt-include
--without-opt-include=${opt-dir}/include
--with-opt-lib
--without-opt-lib=${opt-dir}/lib
--with-make-prog
--without-make-prog
--srcdir=.
--curdir
--ruby=/.../.rvm/rubies/ruby-1.9.1-p378/bin/ruby
--with-sqlite3-dir
--without-sqlite3-dir
--with-sqlite3-include
--without-sqlite3-include=${sqlite3-dir}/include
--with-sqlite3-lib
--without-sqlite3-lib=${sqlite3-dir}/lib
--with-sqlite3lib
--without-sqlite3lib
checking my version of sqlite3 I found that it was out of date.
$sqlite3 -version
3.4.0
I then located my outdated version:
$which sqlite3
/usr/bin/sqlite3
and then manually installed a newer version with the "--prefix" options pointing to the location of my current install ("/usr")
$ curl -O http://www.sqlite.org/sqlite-3.6.16.tar.gz
$ tar xzf sqlite-3.6.16.tar.gz
$ cd sqlite-3.6.16
$ ./configure --prefix=/usr
$ make
$ sudo make install
After that it's just a simple:
gem install sqlite-ruby
I am a Rails developer. That is the only platform and programming I have approached seriously as of the writing of this post. So although I have strong opinions, one might say that I am greatly missing the bigger picture. None the less, here are my thoughts.
I hate gems. I hope to never use them ever again. I am aware that I am greatly outnumber by the Rails community with this opinion, but I have not heard anything that seems worth changing my mind.
The main problem I have with gems presents itself when trying to get the environment for your app functional on multiple machines be it your server or other development machines. Issues I've had:
- Forget to install the gem on the server and so the server goes down when I deploy
- When joining a new project I simply cannot find the gem/version to install it.
True, the first one is do to my incompetence because I'm flawed, but who isn't? I want a foolproof plan, and plugins solve that problem.
Furthermore, who wants to ssh into their server to install the gem anyway? Personally I prefer to stay away from ssh as much as I can and by using plugins, that's one less library I have to make the extra trip to install on the server.
True, plugins take up more space on your hard drive considering the repetition, but who's really counting people? It is far worth it to me in order to have a cleanly packaged application that just works without a bunch of dependencies.
Being minority in this opinion, we are now seeing a lack of support for plugins as the Rails bigwigs are abandoning their plugins to focus more on their gems. So now the question must be asked, "How do I convert a gem to a plugin?". Well, I did a little googling to see what I could find and found nothing. So I guessed. I wanted to install the htmlentities library which is only offered as a gem so first I did
script/generate plugin htmlentities
Then I simply copied the gem files over to :rails_root/vendor/plugins/htmlentities replacing any duplicate directories such as "lib" and "test".
I have no idea if this is an efficient or appropriate way to convert a library, but it worked, so my research stops there.
If you are an avid Declarative Authorization user then you have probably run into the issue where you want your users to be able to link to their page from http://localhost:3000/gabeodess.
So you go about your normal routine and set up to_param and change find to find_by_login, but then Declarative Authorization complains that:
Couldn't find User with ID=gabeodess
When using filter_access_to there is a handy option to handle this with :load_method, this however is not supported in filter_resource_access. I was unable to find any documentation on how to handle this for filter_resource_access. After digging through the code a bit I found that filter_resource_access actually checks the controller for a :load_#{controller_name} method before loading the object so I added
protected
def load_user
@user = User.find_by_login(params[:id])
end
to my users_controller and problem solved.
In trying to figure out why cron is refusing to run my s3backup script (even though it runs fine outside of cron and cron runs my other commands) I did a "locate cron | grep log" as a first step in debugging. This returned nothing useful. Turns out on some systems cron will log info to /var/log/syslog. So if you can't find your cron log, try looking there.
Install id3lib:
$ sudo port install id3lib
Install id3lib-ruby:
$ sudo env ARCHFLAGS="-arch i386" gem install id3lib-ruby -- --build-flags --with-opt-dir=/opt/local
Thanks to HickoryTech for that solution!
The issue arose when trying to run finders on my ActiveResource models:
>> MyModel.find(10)
NoMethodError: You have a nil object when you didn't expect it!
You might have expected an instance of ActiveRecord::Base.
The error occurred while evaluating nil.[]
from /Library/Ruby/Gems/1.8/gems/activeresource-2.3.5/lib/active_resource/base.rb:411:in `prefix'
from /Library/Ruby/Gems/1.8/gems/activeresource-2.3.5/lib/active_resource/base.rb:472:in `element_path'
from /Library/Ruby/Gems/1.8/gems/activeresource-2.3.5/lib/active_resource/base.rb:657:in `find_single'
from /Library/Ruby/Gems/1.8/gems/activeresource-2.3.5/lib/active_resource/base.rb:586:in `find'
from (irb):8
The problem turned out to be that I had neglected to include the protocol in my
self.site declaration.
Thus by simply changing,
class MyModel < ActiveResource::Base
self.site = 'localhost:3000'
end
to:
class MyModel < ActiveResource::Base
self.site = 'http://localhost:3000'
end
Problem solved.
Here's a handy tool picked up from pedropimentel.com.
Add this to your .irbrc file (if it doesn't exist in ~/ then "touch ~/.irbrc"):
def show_sql
ActiveRecord::Base.logger = Logger.new($stdout)
ActiveRecord::Base.connection_pool.clear_reloadable_connections!
end
Now if you ever want to see the SQL generated from your queries while in console just run:
>> show_sql
=> []
>> Impression.count
SQL (0.1ms) SET client_min_messages TO 'panic'
SQL (0.1ms) SET client_min_messages TO 'notice'
SQL (1.4ms) SELECT count(*) AS count_all FROM "impressions"
=> 31
Done.
If you are getting this error:
Media item /var/folders/VV/VVS4xDN+GTmqAn+OjaguJU+++TI/-Tmp-/_featuredCNN,1596,2.jpg is not recognized by the 'identify' command.
... it is possible that your paperclip plugin simply does not know where to find your installation of ImageMagick. In my case, I installed ImageMagick using macports and it is located in /opt/local/bin. Placing the following in config/initializers/paperclip.rb solved this issue for me:
Paperclip.options[:image_magick_path] = '/opt/local/bin' if Rails.env.development?