Merb bundler
Merb is increasingly impressive. These guys are amazing. Check out the bundler.
codes a lot
If the code is inexplicably missing from some of my posts it is because gist.github.com is down at the moment. Check back a little later.
Merb is increasingly impressive. These guys are amazing. Check out the bundler.
Basic user Signup with MerbAuth
Datamapper documentation - Unlike Rails you can choose your ORM and unlike Rails the ORM docs are stored outside of the core Merb documentation. This is the link to the documentation of the ORM of my choice.
Difference between render and display in merb
MerbCamp video
Merbcamp recap(s)
MerbAuth Basics - before :ensure_authenticated, :exclude => :index
Here’s how to handle dynamic subdomains in Merb in the router.
Merb does not have a simple_format helper like in Rails so you can do the following.
Add this to your Application Helper
1 2 3 4 5 6 7 8 9 10 11 | def simple_format(text, html_options={}) text = text.to_s.dup text.gsub!(/\r\n?/, "\n") text = text.split(/\n\n+/) formatted_text = "" text.each do |line| line.gsub!(/([^\n]\n)(?=[^\n])/, '\1<br />') formatted_text << tag(:p, line, html_options) + "\n\n" end formatted_text end |
Use in your view
<%= simple_format(@page.body) %>
<%= simple_format(@page.body, :class => ‘hello’) %>
Thanks goes to matteti for enlighting me on the fact that I could start with the rails simple_format helper and configure as necessary.
Here’s how to see your routes in merb using rake and irb.
It’s similar to rake:routes in rails.
1 | rake audit:routes |
Or in irb
merb -i merb.show_routes
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-mailer", 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 = “you@domain.com”‘ at the end of those files.
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=testThen 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
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.
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> |
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); } |
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.
(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.
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
sudo gem install erubis rake json_pure rspec rack hpricot mime-types ruby2ruby ParseTree memcache-client templater haml mailfactory sequel mongrel libxml-ruby english addressable builder
We will use thor to track Merb from git HEAD - which just means that we will keep up with the latest development version.
mkdir ~/sources cd ~/sources git clone git://github.com/wycats/thor.git cd thor rake install
I like to keep my code projects in their prospective framework/language folder. (i.e. in ~/documents/code/rails are my rails apps and in ~/documents/code/merb are my merb apps). I am going to put the merb.thor file in this merb folder.
cd ~/documents/code/merb/sources curl -L http://merbivore.com/merb.thor > merb.thor
First, make sure you have the latest merb.thor file. Run this command again.
cd ~/documents/code/merb/sources curl -L http://merbivore.com/merb.thor > merb.thor # or alternatively you can run thor merb:tasks:update
Install/update merb:edge
cd ~/documents/code/merb/sources #sudo thor merb:edge --install #used this previously but now using the 3 following lines so that I get the merb-plugins gems like merb_helpers in there as well. sudo thor merb:edge:core --install sudo thor merb:edge:more --install sudo thor merb:edge:plugins --install
You will get an output similar to this if installing for the first time.
Aside:
What is an orm? It’s an object-realtional_mapping tool/language. ActiveRecord is the most well known if you are a rails developer. Datamapper seems to be the current most popular choice for merb developers (but don’t quote me on that. Merb is highly configurable and different orms - like ActiveRecord - might server your particular needs better). However, datamapper is a safe bet for now with it’s goal to be fast, thread-safe and feature rich. Plus, thor supports it. On a final note, if you don’t know which orm to use, use datamapper. It is awesome. Let wycats show you why.
cd ~/documents/code/merb/sources sudo thor merb:edge:dm_core --install sudo thor merb:edge:dm_more --install #the following worked on my computer already installed with datamapper, but did not work on a fresh install on a server. Therefore, use the two lines above. #thor dm:gems:wipe #to clean out any old datamapper gems #thor dm:clone #to pull down the github datamapper repositories #cd dm #thor dm:install #to install the latest datamapper gems
However, the most recent Thor file did not install merb_datamapper (Sept 23 2008), therefore I also did:
cd ~/sources git clone git://github.com/sam/dm-more.git cd dm-more/merb_datamapper rake install
Also, the most recent data_objects and do_mysql was not installed correctly (I was getting the uninitialized constant DataObjects::URI (NameError) like you see here)so I also did:
cd ~/sources git clone git://github.com/sam/do.git cd do rake install