Tuesday, September 30, 2008

Setting up ssh keys

At the command line on your local computer
1. ssh-keygen -t rsa
2. Enter a passphrase
3. scp ~/.ssh/id_rsa.pub user@remotehost.com:~/.ssh/id_rsa_temp.pub
(will need to enter your password for user@remotehost here)
Then
4. ssh user@remotehost
5. chmod ~/.ssh 700
6. cat ~/.ssh/id_rsa_temp.pub >> ~/.ssh/authorized-keys
7. rm ~/.ssh/id_rsa_temp.pub
8. chmod 600 ~/.ssh/authorized_keys (not strictly necessary)
9. log out of your shell
10. log back in
11. ssh user@remotehost.com (should now be prompted for key passphrase)

To set it up so you can log in with no passphrase:
1. ssh-agent bash
2. ssh-add (then enter key passphrase)
3. ssh user@remotehost.com

Ferret on shared hosting

I'm using ferret for a full text search on an app deployed on site5. These are the steps I took to get it set up:

1. Install the ferret gem

2. Tell the rails app where to find the gem:
# config/environment.rb
# Be sure to restart your server when you modify this file

# Uncomment below to force Rails into production mode when
# you don't control web/app server and can't set it the proper way
ENV['RAILS_ENV'] ||= 'production'

if ENV['RAILS_ENV'] == 'production'
ENV['GEM_PATH'] = '/home/forfolks/gems:/usr/lib/ruby/gems/1.8'
end


It seems that it is necessary to do this in environment.rb and not in config/environments/production.rb.

3. On shared hosting you can't run daemons so the DRb server approach for updating the ferret index won't work. I followed instructions here to set up a rake tast to update the index instead. I also commented out the production part in config/ferret_server.yml.

  # app/models/product.rb
def before_save
# disable automatic ferret indexing...move it to a cron job
self.disable_ferret(:always)
end


# ferret_index.rake
desc "Updates the ferret index for the application."
task :ferret_index => [ :environment ] do | t |
Product.rebuild_index
# here I could add other model index rebuilds
puts "Completed Ferret Index Rebuild"
end


I then call this in my code via:
    system "rake ferret_index &"

as detailed in this railscast.

Tuesday, September 16, 2008

Rails ActionMailer on Site5 2

So, it turned out that it wasn't as straight forward as I thought. I dumped the config stuff after the 'Rails::Initializer.run do |config| ' part in environment.rb and tried to send an email. The server timed out and gave a 'Rails Application failed to start' error, which meant that the fcgi process was being killed (I looked in the site's error log in Backstage to figure this out.)

Couldn't work out what was going on, because it had worked in the console. Eventually I went back to the console. I tried
ActionMailer::Base.smtp_settings

to see what settings it was reading. It dumped a load of default-looking settings to the command line. Somewhere my configuration settings were being over-ridden.

Eventually I discovered that this was happening in config/initializers/mail.rb. It seems that the initializers are run after the main initializer stuff in environment.rb. I put my config stuff in there instead and it worked :) .

Wednesday, September 10, 2008

Rails ActionMailer on Site5

ActionMailer is the rails class that allows you to send emails from within a rails app. To get it working I did the following:

1. Visit the 'Backstage' admin area and create an email account for 'email_user' with password 'email_password'. At this point it should tell you the SMTP server is 'mail.mydomain.com'.

At this stage I decided that I would try to get it working in the console first. So I went to my application root and typed 'script/console production' and then

2. Set the configuration

ActionMailer::Base.delivery_method = :smtp
ActionMailer::Base.smtp_settings = {
:address => "localhost",
:port => 25,
:authentication => :login,
:user_name => 'email_user+mydomain.com',
:password => 'email_password'
}


3. Created a mailer

class Page < ActionMailer::Base
def about
recipients 'tom.closeman@gmail.com'
subject "Wey hey - it works - again"
from "email_user@forfolkssake.com"
end
end


This relied on the (blank) template 'App/Views/Page/about.html.erb' existing in my application folder.

4. Sent the message
 Page.deliver_about 


This then sent me the message. Which I thought was pretty cool.

Copying production data to development environment

I wanted to copy all the data from the production environment on the server to my development environment on my laptop. The following worked:

1. In the Backstage area of site5 choose SiteAdmin > Web Site Tools > Download an SQL database backup and then choose the development database.

This produces an SQL dump of the database and all the data therein.

2. Download and save this file (say we save it as 'production_dump.sql' in 'some_path')

3. Run the following


mysql -h localhost -u root -p password myapp_development < some_path/production_dump.sql


(Syntax is "mysql -hHOSTNAME -uUSER -pPASSWORD DATABASE < DUMPED_TEXTFILE")

4. Download any files that may have been uploaded to the server using facilities such as attachment_fu.

Monday, September 8, 2008

Making methods available to helpers

I recently followed the instructions here to help set up restful authentication on an application. As part of the process an 'authenticated_system.rb' file is added to the 'lib' folder containing the module 'AuthenticatedSystem'. This is then included in the application with the line
 class ApplicationController < ActionController::Base
...
include AuthenticatedSystem


I wanted some of my views to change depending on whether on not someone was logged in as an admin. The module provided me with a logged_in? function that I could use like this to check if someone was logged_in so I thought it would be pretty straight-forward. I dutifully created an admin? function in the AuthenticatedSystem module and tried to use it in my views/helpers. Unfortunately this gave me the following error:
undefined method `admin?' for #


It turned out what I was missing was the equivalent to this:

# Inclusion hook to make #current_user and #logged_in?
# available as ActionView helper methods.
def self.included(base)
base.send :helper_method, :current_user, :logged_in?
end


I think what is happening here is that we're actually modifying (adding methods to) the base instance of the class we're being placed into (presumably ActionController::Base). Normally when including a module the methods are just added to the current class. Somehow the methods in ActionController::Base seem to be available to the Helpers/Views (ie find their way into ActionView) whereas those just added to the ApplicationController don't.

Sunday, September 7, 2008

Useful rails things

Group by week: As described here, in rails enumerable objects have a group_by method so you can do things like:

<% @posts.group_by(&:week).each do |week, posts| %>
<div id="week">
<h2>Week <%= week %></h2>
<%= render :partial => 'post', :collection => @posts %>
</div>
<% end %>