Notes on migrations

Posted by topher
on Tuesday, November 13

If you add columns to a model, and you want to use that model, call Base#reset_column_information.

If you save a model in a migration, and if you do not want the timestamps (created_at, updated_at) to be updated, put ActiveRecord::Base.record_timestamps = false.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class AddLastCommentAtToTopic < ActiveRecord::Migration
  class Topic < ActiveRecord::Base
    has_many :posts
  end
  
  class Post < ActiveRecord::Base
  end
  
  def self.up
    ActiveRecord::Base.record_timestamps = false
    add_column :topics :last_comment_at, :datetime
    Topic.reset_column_information
    Topic.find(:all).each do |topic|
      topic = topic.posts.find(:first, :order => "last_comment_at DESC")
      if topic
        topic.last_comment_at  = post.last_comment_at
        topic.save
      end
    end
    ActiveRecord::Base.record_timestamps = true
  end

  def self.down
    remove_column :topics, :last_comment_at
  end
end

Send emails in development environment using Gmail

Posted by topher
on Monday, November 12

If you don’t have a mail server in your development machine, you can use Gmail. Put the following code in RAILS_ROOT/lib/smtp_tls.rb

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
require "openssl"
require "net/smtp"

Net::SMTP.class_eval do
  private
  def do_start(helodomain, user, secret, authtype)
    raise IOError, 'SMTP session already started' if @started
    check_auth_args user, secret, authtype if user or secret

    sock = timeout(@open_timeout) { TCPSocket.open(@address, @port) }
    @socket = Net::InternetMessageIO.new(sock)
    @socket.read_timeout = 60 #@read_timeout
    #@socket.debug_output = STDERR #@debug_output

    check_response(critical { recv_response() })
    do_helo(helodomain)

    if starttls
      raise 'openssl library not installed' unless defined?(OpenSSL)
      ssl = OpenSSL::SSL::SSLSocket.new(sock)
      ssl.sync_close = true
      ssl.connect
      @socket = Net::InternetMessageIO.new(ssl)
      @socket.read_timeout = 60 #@read_timeout
      #@socket.debug_output = STDERR #@debug_output
      do_helo(helodomain)
    end

    authenticate user, secret, authtype if user
    @started = true
  ensure
    unless @started
      # authentication failed, cancel connection.
      @socket.close if not @started and @socket and not @socket.closed?
      @socket = nil
    end
  end

  def do_helo(helodomain)
     begin
      if @esmtp
        ehlo helodomain
      else
        helo helodomain
      end
    rescue Net::ProtocolError
      if @esmtp
        @esmtp = false
        @error_occured = false
        retry
      end
      raise
    end
  end

  def starttls
    getok('STARTTLS') rescue return false
    return true
  end

  def quit
    begin
      getok('QUIT')
    rescue EOFError, OpenSSL::SSL::SSLError
    end
  end
end
Then, add these at the bottom of RAILS_ROOT/config/environments/development.rb
1
2
3
4
5
6
7
8
ActionMailer::Base.server_settings = {
  :address => "smtp.gmail.com",
  :port => 587,
  :domain => "mycompany.com",
  :authentication => :plain,
  :user_name => "username",
  :password => "password"
}

Add your username and password, restart the server and you’re good to go. Note that the emails your app sends might end up in the bulk folder.

Link How to use GMail SMTP server to send emails in Rails ActionMailer