Last night I spent way too much time getting this whole deal working for an initial deployment. Heroku has always been one of the easiest ways to get Rails applications on a server and running, but working on this new idea with Rails 3.1 and the rails-admin engine was a bit trying.
If you have not used Rails-admin yet I suggest you check it out. The interface is highly intuitive and it creates a well designed admin for any CMS style application. Our application has a need for admins to do work in an area separate from the general signed in user. In other applications I have achieved this with roles and I see no difference here with the exception that I wanted to use rails-admin for the administrators and not the general user, or member.
The READMEs for devise and rails-admin setups are pretty good for set so I won’t go into them here.
Part One: The stupidness begins…
After the basic project is setup, the next thing I did was create a role field on the on the user column. In some applications this can be a boolean, but we may need many roles later one so I went with an integer.
#cmd-line $ rails generate migration AddRolesToUsers #gvim rails_app/db/migration/last_migration_bla_blah.rb class ChangeUserRoleDefaulttoOne < ActiveRecord::Migration def change add_column :users, :role, :integer, :default => 1 end end #cmd-line $ rake db:migrate
Now I need to make the rails-admin area unreachable for users that are not administrators. Create a file in config/initializers/rails_admin.rb and add the following. The part that tricked me here was the “warden.user.role”. I assumed it would be something like current_user, foolish right!? Anyway this information is in the awesome readme of rails-admin at the very bottom.
#gvim config/initializers/rails_admin.rb RailsAdmin.config do |config| config.authenticate_with do redircet_to root_path unless warden.user.role.eql?(3) end end
Now I have an admin area that can only be accessed by admins. New users who create an account can only access pre-determined areas prefixed in the controller with basic devise authentication checks.
#gvim app/controllers/some_controller.rb class SomeController < ApplicationController before_filter :authenticate_user! end
Except it doesn’t work! Apparently my sign_out path for devise is messed up. This has never been an issue before and I forget all the details, but here is the error and solution.
No route matches [GET] "/users/sign_out" devise 3.1 rails
WTF? When I run
$ rake routes
My link_to ‘Logout’ looks normal.
# app/views/layouts/application.haml.html %p= link_to('Logout', destroy_user_session_path) if current_user
But… apparently with Rails 3.1 you need to configure the config/initializers/devise.rb
# The default HTTP method used to sign out a resource. Default is :delete. config.sign_out_via = :get
Snap! Now that works.
Part Two: The stupidness continues…
Not even thinking the Heroku/Rails mix wouldn’t fire away the first time with no configuration I pulled one of these:
#cmd-line $ heroku create my_app $ git add . $ git commit -m 'going to heroku' $ git push heroku master
Things seemed ok, but the app won’t start quite yet
What is this? There is a Stackoverflow ticket about the issue here, but it doesn’t solve the issue. The solution describes adding this GEMFILE
group :production do gem 'therubyracer-heroku', '0.8.1.pre3' end
This is not recommended by Heroku and leaves one to wonder how this new asset pipeline system is going to work on Heroku. Luckily Heroku has created a stack named Cedar, which is in beta, for Rails 3.1 applications. With this knowledge I start with a migration of my stack.
$ heroku stack:migrate cedar
But.. this doesn’t work either. In order to use the beta Cedar stack you have to create a new Cedar instance – no migrating allowed.
$ heroku create my_app_2 --stack cedar
Now edit your git config to point to your newly created Heroku app.
#cmd-line $gvim .git #.git/config [core] repositoryformatversion = 0 filemode = true bare = false logallrefupdates = true ignorecase = true [remote "origin"] fetch = +refs/heads/*:refs/remotes/origin/* url = email@example.com:username/my_app.git [branch "master"] remote = origin merge = refs/heads/master [remote "heroku"] url = firstname.lastname@example.org:my_app_2.git fetch = +refs/heads/*:refs/remotes/heroku/*
Woot! getting closer, but don’t forget the ‘pg’ gem in your Gemfile. If you are using a DB other than ‘pg’ in development make sure you wrap that a development group in your gemfile too or Heroku with kick your app back.
#GEMFILE group :production do gem 'pg' end group :development do gem 'sqlite3' end
We also need to add a path variable to our heroku config
heroku config:add PATH=vendor/bundle/ruby/1.9.1/bin:/usr/local/bin:/usr/bin:/bin:bin
#cmd-line $ git add . $ git commit -m 'going to heroku' $ git push heroku master $ heroku run rake db:migrate //Cedar needs this extra "run" command $ heroku run db:push
Snap! Now I have my app, schema, data, and authentication set up on Heroku. That took way to long to figure out, too long to write this post, so I hope it finds someone and helps.
Lesson learned, “Don’t assume Heroku knows which stack to create with your application.” It doesn’t know and you have to know what you are deploying to make your specific application work.