Rails 3 Mail gem error creating mail

Posted by unixmonkey on September 15, 2011

I’m in the process of upgrading a Rails app from 2 to 3, and this proved to be a stumbling block.

Creating a message of any kind would result in a message like this:

NoMethodError: undefined method `new' for "smtp":String
from gems/mail-2.2.15/lib/mail/message.rb:252:in `delivery_method'
from gems/actionmailer-3.0.0/lib/action_mailer/delivery_methods.rb:74:in `wrap_delivery_behavior'
from gems/actionmailer-3.0.0/lib/action_mailer/delivery_methods.rb:83:in `wrap_delivery_behavior!'
from gems/actionmailer-3.0.0/lib/action_mailer/base.rb:641:in `mail'
from app/mailers/developer_mailer.rb:22:in `email_error_message'

This behavior comes from a method named lookup_delivery_method in the Mail gem.
The problem is that this method assumes the ActionMailer::Base.delivery_method to return a symbol like :smtp instead of a string like “smtp”. The old behavior worked fine in Rails 2.x apps.

I have different mailer settings per environment and load the settings in pretty much the same way Redmine does, by looping over a yml config file and using send to set actionmailer settings. The solution is to make sure it is created as a symbol like so:

# Loads ActionMailer settings from config/email.yml
# and turns deliveries on only if configuration block is found
config_file = Rails.root.join('config','email.yml')
 
if File.file?(config_file)
  mailconfig = YAML::load_file(config_file)
 
  if mailconfig.is_a?(Hash) && mailconfig.has_key?(Rails.env)
  # enable deliveries
  ActionMailer::Base.perform_deliveries = true
 
  mailconfig[Rails.env].each do |key, value|
    if value.respond_to?(:symbolize_keys!)
      value.symbolize_keys!
    elsif value.respond_to?(:to_sym)
      value = value.to_sym
    end
    ActionMailer::Base.send("#{key}=", value)
  end
else
  # disable deliveries
  ActionMailer::Base.perform_deliveries = false
end

I’m in love with :symbol.to_proc

Posted by unixmonkey on August 06, 2010

I’ve been crawling over this Rails project and lately finding lots of places where clarity could be increased by using symbol_to_proc, so I thought I would share it a bit for those not in the know on this handy ruby shortcut.

Rails added symbol_to_proc shorthand in version 1.1, and it is such a nice shortcut, that it became part of the Ruby language in version 1.8.7

So, anywhere you would normally use an iterator with a block like so:

people.collect { |p| p.name }

could be shortened to call like:

people.collect(&:name)

The difference may not look so dramatic in the above example, but how about this one:

   # classic
   prison.inmates.select{ |i| i.repeat_offender? }.select{ |i| i.offsenses }.collect{ |o| o.prosecution_fees }.sum

   # to_proc
   prison.inmates.select(&:repeat_offender?).select(&:offenses).collect(&:prosecution_fees).sum

Some people, including Rails core member pratik (http://m.onkey.org/2007/6/30/let-s-start-with-wtf)
Have criticized and advised against using this shortcut because it is roughly 4 times slower than doing without its syntax sugar.

Now, I would rather have a beautiful, understandable code base than a particularly fast one (after all, I *am* using Ruby), but the reason for the slowness is largely because of the implementation as shown below:

  class Symbol
    def to_proc
      Proc.new { |*args| args.shift.__send__(self, *args)
    end
  end

This implementation looks for arguments passed in and shifts self off of them before calling.
This allows for calling a method with arguments like so:

[1,2,3].inject(&:+)

I believe this represents a real edge case at the expense of a lot of speed, and Luke Redpath (http://lukeredpath.co.uk/blog/optimising-symbol-to_proc.html) has a lot of good to say about the topic, and even goes as far to present a patch for how this should be implemented for pure speed:

  class Symbol
  def to_proc
    @to_proc_proc ||= Proc.new { |obj| obj.__send__(self) }
  end
end

I’ve patched this in to my Rails project and not a single one of my tests failed, your mileage may vary, but even without the speed boost, I’ll continue to use :symbol.to_proc because I love it so.

Rails respond_to rendering wrong format in IE 2

Posted by unixmonkey on August 02, 2010

I ran into an interesting issue today where a client viewing my Rails site would go to a link; and instead of seeing the html view rendered, it was skipping right to an alternate format in the respond_to block.

Clicking a link going to /orders, was instead taking them to /orders.xls, which I have in a respond_to block like so:

  def orders
    @orders = Order.all
    respond_to do |format|
      format.html # new.html.erb
      format.xls   # new.xls.erb
    end
  end

The client in question was using Internet Explorer. This provided a major clue.
It turns out that IE will send an HTTP_ACCEPT header listing all the stuff it can accept in the browser, and thus, because it can accept .xls files, it requests that format.

I’m experiencing this in a Rails 2.3.8 app, but documentation at railsguides.info states this behavior was changed in Rails 2.2. Perhaps an older plugin is switching it back on, I’ll have to investigate.

In any case, adding this line to application.rb solves the problem:

config.action_controller.use_accept_header = false

This causes it to behave as expected, where it uses the file extension alone to determine the format when there is a question which format to use.

ActiveRecord Query Building with Multiple and Optional Conditions 8

Posted by unixmonkey on December 29, 2008

For some complex searches, I find myself needing to build a query with some optional conditions that may or may not exist based on search terms.

I could concatenate an SQL string, but when we are dealing with user-supplied input, we need to parameterize the sql query with question marks (?) for binding parameters to to avoid SQL injection attacks.

But I may not know how many parameters I’m actually going to use in a query.

With a form like this:

Show me my friends: 
  living in: [   ]
  whose hobby is: () skating, () fishing, () basketball
  over: [  ] years old

  *(no required fields)

At first stab, you could try something like this:

User.friends.find(:all, :conditions => [
   'town LIKE ? AND hobby = ? AND age >= ?', 
   "%#{params[:town]}%", params[:hobby], params[:age] 
])

This would work, but only if all fields are filled out; otherwise the SQL generated would break looking like this if someone only filled in the name part of the form:

"SELECT * FROM users WHERE town LIKE "%indianapolis%" AND hobby = '' AND age >= ''"

There are some plugins like Ezra’s Ez-Where to handle query building; but how about we try using the built-in symbol key interpolation as described here in ActiveRecord to get the job done.

This lets you use named :symbols in place of question marks for binding.

Find lets you supply your conditions as a 2-element array with a string, and a corresponding hash like so:

User.friends.find(:all, :conditions => [ 
  'town LIKE :town AND hobby = :hobby AND age >= :age', 
  { :town => "%#{params[:town]}%" , :hobby => params[:hobby],  :age = params[:age] }
])

Again, this will work just fine if all fields are filled out; but how do we omit conditions and hash keys?

Our final SQL string can be built by joining conditions with AND (or OR if your app suggests it), and stuffing new key/value pairs into our arguments hash, or with Hash.merge!

First we’ll set up our search method like so:

def results
  conditions  = []
  arguments = {}
 
  unless params[:town].blank?
    conditions << 'town LIKE :town'
    arguments[:town] = "%#{params[:town]}%"
  end
 
  unless params[:hobby].blank?
    conditions << 'hobby = :hobby'
    arguments[:hobby] = params[:hobby]
  end
 
  unless params[:age].blank?
    conditions << 'age >= :age'
    arguments[:age] = params[:age]
  end
 
  all_conditions = conditions.join(' AND ')
 
  @user_friends = User.friends.find(:all, :conditions => [all_conditions, arguments])
end

An alternative is to use Hash.merge! like so:
(this will let you assign more than one key/value pair at a time or to combine hashes)

instead of:

arguments[:town]  = "%#{params[:town]}%"
arguments[:hobby] = params[:hobby]
  arguments.merge!({ 
    :town  => "%#{params[:town]}%",
    :hobby => params[:hobby]
  })

Maybe not as elegant as using a plugin, but certainly clear and flexible.

I’ve got some ActiveRecord in my Shoes 10

Posted by unixmonkey on November 18, 2008

I’ve been playing around with Shoes (shoooes.net) lately as a way to put a cross-platform graphical user interface (GUI) on some of my small purpose-built command-line ruby scripts.

I find that it is quite easy to get started with, and lends a lot of flexibility to the way your program is structured and displayed. However, the structure feels a little bit alien compared to everyday ruby, and there are some gotcha’s you need to keep in mind while developing for Shoes.

I feel I must preface this article by saying that Shoes has excellent documentation, _why (the lucky stiff) turns documentation into its own art form. The manual, “Nobody Knows Shoes” reads a lot like a comic book, full of _why’s own original artwork and clippings from old-timey photos and art, and is complimented by the documentation at help.shoooes.net

I had a bit of trouble at first getting ActiveRecord to interface with a database from a straight port from one of my console apps because I glossed over the parts of the manual that detail the tricky behavior of the garbage collector reaping predefined classes after the app’s initial load.

The fix is pretty simple. Stick all your classes in an external file (or many) and load them using ‘require’.

Anyhow, here is a barebones example of a working implementation for using ActiveRecord in Shoes:

# in foo.rb
class Foo < ActiveRecord::Base
end
 
#in app.rb
Shoes.setup do
  gem 'activerecord'
  require 'active_record'
  ActiveRecord::Base.establish_connection(
    :adapter   => 'sqlite3',
    :dbfile    => 'foos_db.sqlite3'
  )
  require 'foo'
end
Shoes.app do
  @foos = Foo.find(:all)
  para @foos
end

Now, this example requires there is an existing sqlite database with a foos table, change out the establish_connection parameters to connect to any other database. The gem ‘activerecord’ statment tells shoes to install the activerecord gem into the shoes ruby library if it isn’t already there.

If you don’t already have a database, and just want to use a db to act as a storage layer for your app, then you might want to use ActiveRecord::Schema.define to create a database and setup the tables the same way you do for Rails migrations.

Here is a more complete example of an app to keep track of notes using ActiveRecord as the backend. I like the “base class that inherits from Shoes” pattern, so I’m using that here.

# in note.rb
class Note < ActiveRecord::Base
end
 
# in app.rb
Shoes.setup do
  gem 'activerecord' # install AR if not found
 
  require 'active_record'
  require 'fileutils'
 
  ActiveRecord::Base.establish_connection(
    :adapter   => 'sqlite3',
    :dbfile    => 'shoes_app.sqlite3'
  )
 
  # create the db if not found
  unless File.exist?("shoes_app.sqlite3")
    ActiveRecord::Schema.define do
      create_table :notes do |t|
        t.column :message, :string
      end
    end
  end
 
end
 
class ShoesApp < Shoes
  require 'note'
 
  url '/', :index
 
  def index
    para 'Say something...'
    flow do
      @note = edit_line
      button 'OK' do
        Note.new(:message => @note.text).save
        @note.text = ''
        @result.replace get_notes  
      end
    end
    @result = para get_notes
  end
 
  def get_notes
    messages = []
    notes = Note.find(:all, :select => 'message')
    notes.each do |foo|
      messages << foo.message
    end
    out = messages.join("n")
  end
 
end
 
Shoes.app :title => 'Notes', :width => 260, :height => 350

Here’s a screenshot:
notes, the Shoes app

There you are; a cross-platform desktop app that doesn’t require a full-on build environment, and can be distributed with the source exposed for later improvements.

The first time this runs, it installs Activerecord, requires it, establishes a connection, creates the table unless one already exists. Then it shows a form to add notes followed by all the existing notes in the database. Adding a new note refreshes the notes shown.

This isn’t exactly a polished app with full CRUD, but should prove a good introduction to Shoes for someone used to working with ActiveRecord.