Creating a contact form mailer in merb using sendmail and merb-mailer

Posted by scott on November 17, 2008

I posted all this in the wiki here, but in case it changes and simply as documentation for myself, I am reposting it here. Much of it is pieced together from various places.

===== Installation =====
The gem merb-mailer is already installed as part of the standard merb installation via sudo gem install merb. See http://github.com/wycats/merb/tree/master

But if you are missing it, do:

sudo gem install merb-mailer

It will install “mailfactory”:http://mailfactory.rubyforge.org/ gem and “mime-types”:http://mime-types.rubyforge.org/ that mailfactory depends on.

===== Configuration =====
Assuming you created an app using ‘merb-gen app’, merb-mailer will already be listed in config/dependencies.rb. If you started your app using ‘merb-gen core’ then you will need to include merb-mailer as a dependency like the following:

In init.rb, put this at the top

1
require 'config/dependencies.rb'

In config/dependencies.rb

1
2
3
4
5
6
# dependencies are generated using a strict version, don't forget to edit the dependency versions when upgrading.
merb_gems_version = "1.0"
dm_gems_version   = "0.9.6"
 
# For more information about each component, please read http://wiki.merbivore.com/faqs/merb_components
dependency "merb-slices", merb_gems_version

In init.rb configure for sendmail (see below for other config options like smtp). Alternatively, you can put this in development.rb if your production.rb email setup might use smtp instead or vice versa. Development.rb and production.rb will override the init.rb file.

1
2
3
4
5
Merb::BootLoader.after_app_loads do
  # This will get executed after your app's classes have been loaded.
  Merb::Mailer.config = {:sendmail_path => '/usr/sbin/sendmail'}
  Merb::Mailer.delivery_method = :sendmail
end

(Type “which sendmail” to verify where sendmail is located on your machine.)

See http://merbivore.com/documentation/current/doc/rdoc/merb-mailer-1.0/index.html for documented config options.

===== Using Merb mailers =====
Merb separates out its mailers into its only little MVC so things work a little differently than you might be used to with Rails. But it’s for the better.

==== First, setup the mailer. ====

merb-gen mailer contact

This will generate a mailer controller and a mailer view under app/mailers

Open up app/mailers/contact_mailer.rb and make it look like the following:

1
2
3
4
5
6
7
8
class ContactMailer < Merb::MailController
 
  def notify
    @user = params[:user]
    render_mail
  end
 
end

Edit app/mailers/views/contact_mailer/notify.text.erb

1
Tall tube socks with red stripes. The right sock has a large whole near the big toe.

==== Now put the mailer to use inside a controller ====
**Generate a static controller**

merb-gen controller static

**Create an index action and contact action for the static controller**

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Static < Application
 
  # ...and remember, everything returned from an action
  # goes to the client...
  def index
    render
  end
 
  def contact
    send_mail(ContactMailer, :notify, {
      :from => 'yourself@email.com',
      :to => "someoneelse@gmail.com",
      :subject => "Free gym socks. Used!"
    })
 
    render
  end
end

**Make sure your routes are setup properly in router.rb**

1
2
3
4
5
Merb::Router.prepare do
  match('/index').to(:controller => "static", :action => "index").name(:index)
  match('/contact').to(:controller => 'static', :action =>'contact').name(:contact)
  match('/').to(:controller => 'static', :action =>'index')
end

**Make sure your views (static/index.html.erb and static/contact.html.erb) are setup to some degree**

1
2
3
4
5
# index.html
<h2>Home page</h2>
 
# contact.html
<h2>Contacto!</h2>

**Navigate to http://localhost:4000/contact and it should work!**

See http://github.com/wycats/merb/tree/master/merb-mailer for additional details.

It you have problems make sure postfix is running with sudo postfix stop and then sudo postfix start). You should also see the email get sent in your merb development server output. It should look something like the following:

merb : worker (port 4000) ~ notify sent to someoneelse@gmail.com about =?utf-8?Q?Free_gym_socks._Used!?=

===== Creating a contact form =====
This assumes you’ve followed the above instructions so far. This also assumes usage with datamapper.

Create a contact model

merb-gen model contact

Edit models/contact.rb to look like the following:

1
2
3
4
5
6
7
8
9
10
11
class Contact
  include DataMapper::Resource
 
  property :id, Serial
  property :name, String, :nullable => false
  property :email, String, :nullable => false
  property :message, String, :nullable => false
 
  validates_format :email, :as => :email_address
 
end

Edit the static controller’s contact action. This renders the contact page unless the form is submitted using request.post? Then the contact information is saved with datamapper (but not to the database) and our ContactMailer notify action is used to send the mailer.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# static.rb controller
  def contact
    if request.post?
      @contact = Contact.new(params[:contact])
      if @contact.valid?
        send_mail(ContactMailer, :notify, {
          :from => @contact.email,
          :to => 'scott@scottmotte.com',
          :subject => "New message from contact form"
        }, { :contact => @contact})
        render "Thank you. Your message has been sent."
      else
        render :contact
      end
    else
      @contact = Contact.new
      render
    end
  end

Edit the contact action’s view at views/static/contact.html.erb

1
2
3
4
5
6
7
8
<h2>Contact</h2>
<%= error_messages_for @contact %>
<%= form_for @contact, :action => url('contact') do %>
     <p><%= text_field :name, :label => 'Name' %></p>
     <p><%= text_field :email,  :label => 'Email' %></p>
     <p><%= text_area :message, :label => 'Message' %></p>
     <%= submit 'Send' %>
<% end =%>

Your contact form should now send emails and do validations if items aren’t filled in. We still have to pass the values to the emailed message though so let’s take a look at our mailers/contact_mailer.rb and its prospective view to do this.

Edit contact_mailer.rb

1
2
3
4
5
6
7
8
9
class ContactMailer < Merb::MailController
 
  def notify
    # use params[] passed to this controller to get data
    @contact = params[:contact]
    render_mail
  end
 
end

Edit notify.text.erb

1
2
3
4
5
6
7
Name: <%= @contact.name %>
 
Email: <%= @contact.email %>
 
Message:
 
<%= @contact.message %>

**That’s it. You’re done.** You could also customize things a bit here, by creating a global from email in devlopment.rb and production.rb by putting something like ‘SITE_EMAIL = “scott@scottmotte.com”‘ at the end of those files.

Beginner’s guide to installing merb 2

Posted by scott on November 14, 2008

Merb is very cool, but one thing that bothers me is that it is still tough to simply get installed - even at 1.0. The guys working on merb are seriously awesome and amazing. Their progress might even be told in programming history books one day, but installing all the parts of merb has always been a bit painful.

Here’s what I did.

First your gonna need datamapper or the install from merb edge will send a hissy fit.

sudo gem install dm-core dm-more

(hopefully, this will soon just be datamapper - would make more sense)

Then merb:

sudo gem install merb --source http://edge.merbivore.com

Then merb-plugins

cd ~/sources
git clone git://github.com/wycats/merb-plugins.git 
cd merb-plugins
sudo rake install

(hopefully this will become a gem soon too)

You’re also gonna need webrat - even if you don’t end up using it.

sudo gem install webrat

You’re also going to have to create a test database once you setup an app. To do that first edit your database.yml file, then do the following to actually generate that database.

rake db:create MERB_ENV=test

Then run the migrations with:

rake db:automigrate MERB_ENV=test

(there used to be a db:test:clone rake task for this, but it seems to be no more as of this posting so you instead specify the MERB_ENV as the ‘test’ environment)

Now you’ll be able to run autotest

How to install ffmpeg on ubuntu hardy on slicehost

Posted by scott on November 12, 2008

sudo apt-get install ffmpeg

It seems ffmpeg is now distributed through apt-get making things much easier. The above should work just fine.

Originally, I followed these instructions, but to no avail. I then scoured the web trying multiple different steps but still no luck.

On a side not, here’s how to install ffmpeg on mac os x leopard for testing of your app on localhost with ffmpeg.

Explaining the names behind the ubuntu source lists - multiverse, universe, main, restricted

Posted by scott on November 11, 2008

Thanks goes to Ryan52 for his explanation of this on the #slicehost irc.

multiverse is non free not officially supported.
restricted is non free officially supported.
main is free officiaully supported.
universe is non free officially supported.

This information was particularly helpful. I was missing multiverse at the end of my sources list at /etc/apt/sources.list

It looked like this:

deb http://archive.ubuntu.com/ubuntu/ hardy main restricted universe
deb-src http://archive.ubuntu.com/ubuntu/ hardy main restricted universe
 
deb http://archive.ubuntu.com/ubuntu/ hardy-updates main restricted universe
deb-src http://archive.ubuntu.com/ubuntu/ hardy-updates main restricted universe
 
deb http://security.ubuntu.com/ubuntu hardy-security main restricted universe
deb-src http://security.ubuntu.com/ubuntu hardy-security main restricted universe

and now it looks like this thanks to Ryan52s knowledge

deb http://archive.ubuntu.com/ubuntu/ hardy main restricted universe multiverse
deb-src http://archive.ubuntu.com/ubuntu/ hardy main restricted universe multiverse
 
deb http://archive.ubuntu.com/ubuntu/ hardy-updates main restricted universe multiverse
deb-src http://archive.ubuntu.com/ubuntu/ hardy-updates main restricted universe multiverse
 
deb http://security.ubuntu.com/ubuntu hardy-security main restricted universe multiverse
deb-src http://security.ubuntu.com/ubuntu hardy-security main restricted universe multiverse

Then I just ran sudo aptitude update to update my sources list.

I recently had to do this to get download some lib files using apt-get. In particular: http://packages.ubuntu.com/hardy/libdevel/libx264-dev when trying to follow Jim Neath’s tutorial on installing FFMPEG

Site wide announcements in rails

Posted by scott on October 27, 2008

The go to from railscasts but a little out of date since Rails 2.1 implemented timezones

Fixed to work with SQLite and Rails 2.1

Using jquery

How to install postfix on mac os x

Posted by scott on October 20, 2008

Follow these instructions for Mac OS X Postfix SMTP Mail Server Configuration

ajax in place editing with rails 2.1 and jquery

Posted by scott on October 11, 2008

Picture 1.png

Install jrails and jrails_in_place_editing

script/plugin install git://github.com/aaronchi/jrails.git
script/plugin install git://github.com/rakuto/jrails_in_place_editing.git

Setup jrails in application.html.erb

1
2
3
<head>
	<%= javascript_include_tag :defaults %>
</head>

Restart your server

Setup jrails_in_place_editing in the..

1. ..Controller

1
2
3
4
class ProjectsController < ApplicationController
  in_place_edit_for :project, :acreage
  ...
end

2. ..View

1
  <%= in_place_editor_field :project, :acreage %>

That’s it. For more on customization and additional options check out the jrails_in_place_editing readme at:

iPhone optimized Merb application with iUI

Posted by scott on October 01, 2008

Get the latest iui

svn checkout http://iui.googlecode.com/svn/trunk

Inside there is the iui folder. Copy that folder to the public directory of your merb app.

Setup application.iphone.erb

This loads the javascript and css files as well as setting up the toolbar.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
    <title>Title</title>
		<meta name="viewport" content="width=device-width; initial-scale=1.0; maximum-scale=1.0; user-scalable=0;"/>
	  <meta name="apple-touch-fullscreen" content="YES" />
		<link rel="stylesheet" href="/iui/iui.css" type="text/css" media="screen" charset="utf-8" />
		<link rel="stylesheet" href="/stylesheets/iui-custom.css" type="text/css" media="screen" charset="utf-8" />
		<script type="application/x-javascript" src="/iui/iui.js"></script>
</head>
<body>
	<div class="toolbar"> 
    <h1 id="pageTitle"></h1>
    <a id="backButton" class="button" href="#"></a>
    <a class="button" href="#searchForm"></a>
	</div>
 
  <%= catch_content :for_layout %>
</body>
</html>

Add redirect option to iui.js form submit

1
2
3
4
5
6
7
8
9
10
11
12
13
// original
function submitForm(form)
{
    iui.showPageByHref(form.action || "POST", encodeForm(form), form.method);
}
// added from http://cookingandcoding.wordpress.com/2008/09/05/iphone-web-applications-with-iui-and-ruby-on-rails-part-1/
function submitForm(form)
{
    if (form.getAttribute("redirect") == "true")
      form.submit();
    else
      iui.showPageByHref(form.action || "POST", encodeForm(form), form.method);
}

Setup your views

All your views should be named with the iphone extension. e.g. show.iphone.erb or show.iphone.haml, etc.

Most importantly, the iui javascript and css makes some opinions about how you should format your javascript in order to easily retain that ‘iphone look and feel’.

The pdf book “iPhone in Action” is the best resource for this that I could find (check it out at http://www.manning.com/callen/), but you can read through this tutorial on iUI and Rails for the basics of that look and feel.

Add the iphone mime type

(I stole the following from this great tutorial on providing different formats in merb by hassox. Thanks hassox!)

In init.rb put:

1
2
3
4
Merb::BootLoader.after_app_loads do 
  # iPhone mime-type 
  Merb.add_mime_type(:iphone, :to_html, %w[application/xhtml+xml]) 
end

In controllers/application.rb put:

1
2
3
4
5
6
7
8
9
class Application < Merb::Controller 
  before :set_iphone_content_type 
 
   private 
   def set_iphone_content_type 
     self.content_type = :html if self.content_type == :iphone 
     self.content_type = :iphone if request.user_agent =~ /(Mobile\/.+Safari)/ 
   end 
end

That’s it. Reset your local server, and you should now be able to navigate to http://localhost:4000 in iphoney and see your cool new iphone optimized site.

Difference between render and display in merb

Posted by scott on September 24, 2008

Use render for actions like create and new, where you don’t really want to share the xml or even want xml created. Or json for that matter.

Use display to render actions like index and show, where you do want to share the information via xml.

render means you want to render a template — or a string. display means you want to render a resource. so display will do what it can return something to the client

it checks for a template and if that’s missing calls #to_ on the model

# courtesy unagi-san

Here’s the render method on merb-core head and display method on merb-core head

How to uninstall all gems from your computer

Posted by scott on September 23, 2008

sudo gem uninstall --a --ignore-dependencies .+

Thank you loopkid

Also here’s how to uninstall a particular long list of gems. I find this particularly useful for merb which has tons of gems.

1
sudo gem uninstall --a --ignore-dependencies merb.+