Posts Tagged rails3

Working with private RubyGems in Rails 3

I have several gems that contain proprietary code that I do not want public to have access to.    Rubygems.org is great for gem hosting, but they do not allow security restricted gems, since it defeats the purpose of having an open community for ruby gems.  There are several options if you want to host your own gems and restrict access to them.  Here are some of the options that I considered

1. Install gemcutter and use that for a gem server.

2. Install the geminabox sinatra app.  This is a lightweight gem server with a web interface.

3. Use github.  They no longer build gems, but you can still install from github using Bundler (or a plain rake task).

I started playing around with the first 2 options, but I ultimately decided to just use the github solution.  Why waste resources setting up a private server when my code is already stored on github with security.  I am assuming you know how to set up a project on github, password protect it and push your gem source to github.

Git’r tagged

Probably one of the coolest parts of working with gems is being able to install specific versions of a gem in your project.. which is much easier than using vendor plugins.  In order to keep track of your versions you need to work with git tags.  You could also do this with branches, but it would get a bit hairy if you created a new branch for every patch version.  A good example of the proper way to set this up is the Ruby on Rails source on github – > http://github.com/rails/rails.  Click the drop-down where it says “Switch Branches”.  You can see they have a branch for every minor & major version 1.2, 2.0, 2.1, 2.2, 2.3, and 3.0 (master).  But notice that you do not see branches for minor versions like 2.3.8.  They use git tags to keep track of each version instead.  Click “Switch Tags” on the rails source github page.  Here you can see they created a separate tag for each version.  You will want to do the same with your private gems that you host on github.

Jeweler to the rescue

Luckily, jeweler has already done most of the work for us.  Install jeweler first:

gem install jeweler

Jeweler provides some nice shortcuts for creating, building and installing your gems. Take a look at the documentation for more info. I am only going to touch on the versioning that is included with this gem. After you create a project with Jeweler, you get a rakefile that gives you building and versioning tasks. Lets say you make a bunch of changes in your gem project, commit and push them to github and you are ready to bump this gem to a new version. You can use these Jeweler rake tasks to accomplish that:

rake version:bump:patch
#you can also use version:bump:minor and version:bump:major.. 1.2.3 -> 1=major, 2=minor, 3=patch
rake github:release
rake git:release

Jeweler also has a rake task called “release”. This will accomplish the 3 tasks above, but it also tries to push the gem to gemcutter. I could not find a way to turn that off in the documentation (although it may be possible.. I have not looked at the source in depth). I opted to write some custom tasks that combine these 3 tasks into a single task. So I added this to my rakefile:

namespace :version do
  desc "create a new version, create tag and push to github"
  task :github_and_tag do
    Rake::Task['github:release'].invoke
    Rake::Task['git:release'].invoke
  end

  task :patch_release do
    Rake::Task['version:bump:patch'].invoke
    Rake::Task['version:github_and_tag'].invoke
  end

  task :minor_release do
    Rake::Task['version:bump:minor'].invoke
    Rake::Task['version:github_and_tag'].invoke
  end

  task :major_release do
    Rake::Task['version:bump:major'].invoke
    Rake::Task['version:github_and_tag'].invoke
  end
end

The first tasks takes care of the git tag and github commit/push. The other 3 tasks use the first task and add the version bump for major, minor or patch. So now if I want to do a new patch version, I just have to execute one rake task.

rake version:patch_release

That is half of the equation. The other half is installing the gem from github in your Rails 3 project with Bundler.

Bundler takes care of the rest

Bundler ships with Rails 3 and its purpose is gem dependency management. I really like this tool so far, and the development seems to be moving along very fast. I learned a little trick when I was trying to see if something was fixed in Rails Edge. You can specify github as the source of the gem and it will pull the source code from github, build it and install it for you. You can even specify the tag which makes life even easier. So all I have to do is add one line to the Gemfile in my Rails 3 project and install the bundle. Check this out:

Gemfile

gem ‘mygem’, :git => ‘git@github.com:myuserid/mygem.git’, :tag=>”v1.0.2″
bundle install

Now that is easy!

Tags: , , , , ,

Replacing link_to_remote with UJS in Rails 3 (Prototype)

Rails 3 has adopted Unobtrusive Javascript and moved all the _remote functions to a plugin.   They did this in an effort to remove all the inline spaghetti code produced by the helpers and provide a more modular way to deal with Javascript & Ajax. I must admit I like the convenience of the old helpers, but its not really the best way to do things if you are dealing with a complex app that uses alot of Javascript.  So anyways, you will get the following error if you try to use the link_to_remote function:  undefined method ‘link_to_remote’

In order to use UJS in your Rails 3 app, you need to do the following:

1. Use the new javascript file, rails.js along with your favorite javascript framework

In your layout, you can use the default javascript tag to include this and prototype:
The only problem with this method is that it may add javascript files that you don’t need and this adds to page load time.  I like to take advantage of the Google hosted javascripts.  Most people already have them cached and chances are Google will serve the files faster than your hosting company.  I am using some of the scriptaculous libraries so I include that tag too.   Here is what I use:
Make sure you put the rails js tag after prototype.  I wasted 30 minutes figuring that out.

Rails 3 makes it easy to use jQuery or Mootools if you prefer them over Prototype.  Just include them instead.


2. Use the forgery protection meta tags: <%= csrf_meta_tag %>

Rails uses these to prevent XSS attacks.  I don’t know the details, so I will not go into it.. but you need to have this helper which spits out 2 meta tags:
Don’t hard code these.  The helper provides a unique token.

 

3. Change your link_to_remotes to link_to and use the :remote parameter

Lets say you have a list of widgets and people can vote Yes or No as to whether they like the widget.  After they vote, it updates the box with a highlight and changes the text to show you the vote result.  Here is my big ugly Rails 2 version of this:

Here is what you do in Rails 3  (please ignore the ugly path.. we are renovating):

You now use a regular link_to tag and pass the :remote parameter as true.

 

4. Use a js.erb file instead of render :text=>”blah blah”

The link_to tag does not accept :update, :complete, etc., like the link_to_remote tag did.  You can drop in a js.erb file to handle this stuff instead.  I determine the text and color of the highlight in my controller action. /myapp/app/views/widgets/vote.js.erb

Rails sends this back to your page and the javascript is executed.  This is a simplistic solution and the first one I found to produce the same behavior as my original Rails 2 helper.  There may be better ways to do this, but for now this works for me.  Here are some resources that I found useful when figuring this out:

Ryan Bates screencast was very helpful and most of this stuff was “inspired” from that.  Props Ryan, good stuff as usual -> http://railscasts.com/episodes/205-unobtrusive-javascript

Simone Carletti has a good overview on UJS in Rails 3, and is more geared towards jQuery – http://www.simonecarletti.com/blog/2010/06/unobtrusive-javascript-in-rails-3/

Another jQuery example – http://joshhuckabee.com/jquery-rails-3

Tags: , , ,

Performance Exercise #1: Rails Cache = $Cash

As part of my Rails 3 upgrade I am focusing on performance in my app.  The most obvious place to start is caching.  I have a few action caches scattered here in my app, but I neglected to use sweepers in order to cache just about everything.  Rails Sweepers allow you to observe an object in a controller method and expire cache if something changes in your model that warrants a cache expiry.  If your Rails site is mainly a CMS that is 90%+ read-only, you will greatly benefit from caching in Rails.  My app is a public facing read-only site, except for back-end administration stuff.  We add/update/delete content maybe 50-100 times, but most of the content is on pages that can be cached separately.  As a result, we will see a huge performance increase by using action and fragment caching.  It does not look like a whole lot has changed from Rails 2 to 3 according to the edge guides, so you can probably use these techniques on both.

Note: I am using the default caching mechanism that ship with Rails 3 beta4.  Since there are so many out-of-date plugins right now that are not fully compatible with Rails 3, I figured I would not use a plugin for caching.

Types of Caching in Rails

  1. Page Caching – caches page and bypasses application server
  2. Action Caching – caches an action, but still runs through the application server.  application_controller.rb is still executed, but the action in your specific controller is cached
  3. Fragment Caching – caches a fragment of code.  Executes application_controller.rb, widgets_controller.rb.  The caching happens in the view only.

I can’t use Page Caching in my app, because we have some users that login to an account.  If you try page caching with an app like this, then your users will not be able to see dynamic elements of the app that relate to their user account.. and even worse, you risk caching a page for a logged in user, such as an administrator.  Since my app is public facing and has admin accounts, this is not an option.  enter Action Caching…

Action Caching

Action caching is probably your best bet if you have an app with public and private pages.  Action caching will allow you to detect if a user is logged in and decide to cache or not cache.  Lets start with the basics of an action cache:

This will cache your show page, but the cool thing is that it caches each individual object.  So you will have a separate cache for  http://yourapp.com/widgets/1 AND   http://yourapp.com/widgets/2.  This is great, but we are still caching the same page for users who are logged in and users who are not logged in.  This will cause problems, so we need to add a condition to caches_action and a convenience method in the application_controller.  Take a look:

In the application controller, I setup my @user variable based on whether they are logged in. Then I added a cacheable? method. If the user is blank (meaning not logged in), then the action is cacheable, otherwise it is not cacheable (because the user is logged in). Then I am able to use the cacheable? method in the widgets_controller like so:


caches_action allows you to use an if condition. If the :if condition is true, then it caches the action. You must pass a Proc object so that the code is executed at runtime. If this method did not use a Proc, then the code would be executed when the rails code initializes on app server startup.. so basically it would return the same thing every time and it would be useless. The “x” in proc just uses the current object, which is your widgets controller… so the Proc has access to the cacheable? method. Now your actions will be cached if a user is not logged in.  This is a plus for my app, because most of the people that visit my site are public users.  That is great and all, but what if something changes on one of my pages??  I don’t want to use a cached version.  The content on the page will not be fresh.  So what do I do??  This is where sweepers come in to play. Rails Sweeper – A class that observes a model for changes and expires cache based on what changes occur.  You can tell the Sweeper what cache to expire for each type of change. Here is an example class that will show you whats up:
This class is a subclass of ActionController::Caching::Sweeper, which provides it with all the necessary mechanisms to access your controller code and expire the cache.  Notice the first line after the class definition.  You have to include this, so the sweeper knows which Model class to keep an eye on.  Next you see the callback methods.. after_update, etc..  Basically this method says, after you update a Widget instance (widget),  run this code.  The widget variable is the specific widget object that you just updated.  So if you updated widget with the id of 7, you would have access to that variable, just as if you had written “widget = Widget.find(7)”.   This class also has a private method called “expire_cache_for” that all of the callbacks use.  You don’t have to use this private method and you can put any code you want inside the callbacks.  Most of the time it makes sense to use a private method that expires multiple action caches, though.  So in this example, if you create, update or destroy a method, the cache will be expired for that particular object’s show page and the index page as well.

I was wondering where to put the sweeper when I was coding it.  Since I am using Rails 3, I just created a new directory inside myapp/app/ called “sweepers”.  I drop all of my sweepers in here and Rails 3 picks up these classes automatically.  No matter where you place it, you want to make sure these classes get loaded when your server starts.

The sweeper classes are only half of the equation though when dealing with sweeping cache.  You must also add a line to the controller where you want to use the sweeper.  In this example it makes sense to add it to the “widgets_controller.rb”, since that is where the widgets get created,updated, and destroyed.  Take a look at my example:

I added “caches_sweeper” to my WidgetsController. This method takes the sweeper name (WidgetSweeper or :widget_sweeper), and an optional : only parameter. I made the mistake of trying to use : except instead of : only.  caches_sweeper does not know what : except is, so don’t even bother trying.  I’ll put that one on my Rails wishlist.  : only tells the cache sweeper class to only run on these actions.  If you do not use : only, then the sweeper will run on every action in the controller. So thats all you have to do to use action caching with sweeping.   Now lets learn about fragment caching….

Fragment Caching

Now that you have your public facing pages cached, you think to yourself… why should the public have all the fun??  What about my admins that are logged into the system?  Do they get no $cache love?? There are bound to be parts of the application that your logged in users can share, which are not user-specific.  This is where you can use fragments.  Since you don’t want to cache the entire action, you can cache parts of the view.  The only downside to this is that your controller action will be fully executed.  This will probably not be much of a problem if you are using the new Rails 3 query API.  It has lazy loading features built in, so that the database call is only used when it is needed.  If you are just setting up an object or collection without calling any methods on it, the lazy loading feature will not make a database call until the view or helper uses that instance variable.  So my point is, fragment cache in the view will not result in any unnecessary database calls in Rails 3.  Fragment caching is pretty simple.  Take a look at this example html.erb page:

This is about all there is to a fragment cache. You use a block and pass the name to it. If you don’t provide a name to the cache, then it will use “/controller/action” as the default name. You can also get fancy and pass a hash instead like this:

This is helpful if you have more than one fragment in a view and you want to expire them separately. action_prefix will append to the end of the name so you keep them separate. You expire fragment cache in a similar manner to the action caches. Just pass the name or a hash… like so:

Now its time to get crazy with this. My users that are logged in should not cache the same fragments as the non-account users. A helper can achieve that. Check it out:

You can use this helper in place of “cache” in your view like so:

This will use a cache method if the user is logged in, and just yield the block if they are not logged in. So only our logged-in users create and use this cache.

If you want to get really crazy, you can probably cache on a per user basis by appending their user_id to the name. I haven’t tried this and it would probably result in a full cache store for a site with a large user base… but there are endless possibilities when you use helpers with these cache blocks. Same goes for the Proc stuff in action cache.

Sweeping can also be used with the fragment cache and you can use an existing sweeper. Just insert the expire_fragment calls where needed.

So thats about it. These are good techniques to speed up your app without sacrificing fresh content.  A word of caution though:  Analyze your application before and after you add caching.  You need to figure out exactly where the cache expiration should happen and which pages need action vs. fragment caching.  You don’t want to risk stale content on a page because you did not look at all the use cases.  There is no real science to figuring this out.  You just need to look at all of your models and controllers carefully to decide where to use it and think of any odd cases that require cache expiration that may not relate to the same model/controller.  A good example is a storefront with the newest products on the home page.  In this example, you would not only need to expire cache on the product pages, but also the homepage to keep it up to date with any changes & additions that may occur to the products.

So does cache = $cash?? Hell yeah it does. Less database calls = Less CPU cycles = more users on less hardware = less money spent on hosting.

Tags: , , , ,

Setting up Rails 3 on Rackspace Cloud Servers

QUICK UPDATE 03-14-2011 – PLEASE READ – This tutorial was written when Rails 3 was in beta. Some of this info may be outdated. This tutorial will be updated soon, but here are a few notes until I get to it:  For steps 6 & 7, use RVM and install 1.9.2 using RVM. This should install rubygems, so you can skip #7.   For step #8, install without the –pre flag… it will install the current official release (3.0.5 or higher).  I am not using Passenger at this time, so I can’t comment on how well that will work.  You may need to include the bundler Capistrano recipes with your deploy.rb.  This will bundle install with the –deployment flag.

I could not wait patiently for the official release of Rails 3, so I am working on a Rails 3 upgrade now… and part of the process is moving my site from co-location hosting over to Rackspace Cloud.  I am a big fan of the Rackspace Cloud and while most of my websites are hosted there now, I was waiting for my co-location contract to run up before I moved over my highest traffic website.  Here are the steps I used to set up my server. I will show you how to install all the software and create a blank Rails 3 app. Then I will show how to pull an existing Rails 3 app from github and deploy it with Capistrano.

Note: I am not doing this, but you may want to go the route of installing RVM if you will be running multiple applications or ruby versions on your production server.

My Rails stack looks like this:

  • CentOS 5.5
  • Ruby 1.9.2 preview 3
  • Rubygems 1.3.7
  • Rails 3 beta 4
  • Passenger 2.2.15 with Nginx
  • memcached
  • MySQL

Here are the steps I used.  Please leave a comment if you have any questions or if something needs to be changed.

1. Login or signup for Rackspace Cloud Servers (not Cloud Sites)
2. Build a new server – Hosting -> Cloud Servers -> Add Server -> Create a CentOS 5.5 server

(YMMV with other linux flavors using my steps)

3. Login and change your root password
4. Create a new user and add them to the sudoers file.

It is important that you create a new user instead of doing everything as root.  You will most likely run into permission problems with Passenger and Bundler if you do this as root.  Passenger will run as ‘nobody’ if ‘root’ owns the rails app root directory.  It will not have access to root’s local gem bundle. Also, go ahead and disable root login from sshd

useradd app_user
passwd app_user
vi /etc/sudoers  #open sudoers in your favorite text edit
# add the following line below "root ALL=(ALL) ALL" :
# app_user ALL=(ALL) ALL
# save file and exit

#disable root login from ssh, so nobody is able to brute force a root login
vi /etc/ssh/sshd_config
#uncomment "PermitRootLogin yes" and change it to "PermitRootLogin no"
/etc/init.d/sshd restart

#logout and login or su to your new user
su app_user
cd ~
5. Update EPEL and install linux software dependencies
sudo rpm -Uvh http://download.fedora.redhat.com/pub/epel/5/i386/epel-release-5-4.noarch.rpm
sudo yum -y install gcc gcc-c++ make zlib zlib-devel openssl openssl-devel git expect pcre pcre-devel readline-devel mysql mysql-devel libxml2 libxml2-devel libxslt libxslt-devel
6. Install Ruby 1.9.2 preview 3 (compatible with Rails 3 beta 4)
wget ftp://ftp.ruby-lang.org/pub/ruby/1.9/ruby-1.9.2-preview3.tar.gz
tar -xvf ruby-1.9.2-preview3.tar.gz
cd ruby-1.9.2-preview3
./configure
make
sudo make install
ruby -v #just checking to make sure it installed.. output = ruby 1.9.2dev (2010-05-31 revision 28117) [x86_64-linux]
cd ..
7. Install Rubygems 1.3.7
wget http://production.cf.rubygems.org/rubygems/rubygems-1.3.7.tgz
tar -xvf rubygems-1.3.7.tgz
cd rubygems-1.3.7
sudo ruby setup.rb
cd ..
8. Install Ruby on Rails 3 Beta 4

If the official release is out you can remove the –pre. This should install a bunch of gems related to rails 3 beta 4 (23 gems on my system)

sudo gem install rails --pre --no-ri --no-rdoc
9. Create a new directory for your rails applications and create a blank rails app

In rails 3 you need to use the new parameter after the rails command in order to create a new app

mkdir rails_apps
cd rails_apps
rails new myapp
10. Install passenger with Nginx
sudo gem install passenger
sudo passenger-install-nginx-module
# This will guide you thru nginx/passenger install.. hit enter to check dependencies
# choose option 1. Yes: download, compile and install Nginx for me. (recommended)
# I installed in default /opt/nginx.. just hit enter to install default
# hit enter at the end and you should be finished and back to the command line prompt
11. Update your Nginx configuration file so you can run myapp with passenger.

Example Nginx config file:  /opt/nginx/conf/nginx.conf

#I found it necessary to change the user in order to have the correct permissions.
user  app_user;
worker_processes  1;
#error_log  logs/error.log;
#error_log  logs/error.log  notice;
error_log  logs/error.log  info;

events {
  worker_connections  1024;
}

http {
  #Note: rubygems installs gems in the 1.9.1 dir even though I am using 1.9.2... not sure why??
  passenger_root /usr/local/lib/ruby/gems/1.9.1/gems/passenger-2.2.15;
  passenger_ruby /usr/local/bin/ruby;
  # passenger recommends 30 max pool size if you have a 2GB box that is dedicated to app server and
  # less than that if you have a DB server running on it
  passenger_max_pool_size 30;

  include       mime.types;
  default_type  application/octet-stream;
  sendfile        on;
  #tcp_nopush     on;
  keepalive_timeout  65;
  tcp_nodelay        on;
  gzip  on;
  gzip_min_length  1100;
  gzip_buffers     4 8k;
  gzip_types       text/plain;
  gzip_comp_level 2;
  gzip_types      text/css application/x-javascript text/xml application/xml application/xml+rss text/javascript;

  server {
    listen       80;
    server_name  localhost; #putting in localhost just for testing.  You should set this to your domain name: yourdomain.com
    root /home/app_user/rails_apps/myapp/public;
    passenger_enabled on;  #MAKE SURE YOU HAVE THIS LINE OR IT WILL NOT FORWARD TO PASSENGER!
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
       root   html;
    }
  }
}
12. Start Nginx, which will also start Passenger
sudo /opt/nginx/sbin/nginx
13. Open up iptables for port 80 and restart iptables.

Also, you might want to look into enable SELinux for some added security on your system.

sudo vi /etc/sysconfig/iptables
# Add the following line towards the bottom below the port 22 ACCEPT
# -A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp --dport 80 -j ACCEPT
# save and close
# restart iptables
sudo /etc/init.d/iptables restart

You should be able to get to your Rails app now and see the default rails index.html -> Welcome aboard. You’re riding Ruby on Rails! ……

This is great and all, but I am more interested in running my existing app in production, rather than creating a new one. I am guessing you will not be developing on the server, so we need to get things set up with github & capistrano and deploy our app that way. This assumes that you already have a project in github and you have some git knowledge. This also assumes that you already have a database server setup and that your database.yml is pointing to that server. I will not cover database setup here.

Here is what you do:

14. Generate a new ssh key on the server to use with github
ssh-keygen -t rsa -C "youraddress@email.com"
#use the default dir and enter a solid password
15. Add the key to github

Full instructions about creating a key and adding to github here: http://help.github.com/linux-key-setup/

16. Add entry into known_hosts file for github

This is necessary to pull with capistrano. I think the easiest way to do this is to clone your github project. It will create the known_hosts file and add the entry for you. Then you can just delete the project right after you clone it. No need to keep it, since you will be using the Capistrano setup.

git clone git@github.com:your_username/your_project.git
# type yes to accept the key entry
# enter your passphrase
# it will clone.. now delete it
rm -Rf your_project/
OPTIONAL: Out of habit I have all my rails apps in the same place on my servers.

I have a dir called /rails_apps. I am going to create that now, but you can use what you already have set up if you like.  I also need to change the dir to be owned by “app_user”

sudo mkdir /rails_apps
sudo chown app_user:app_user /rails_apps/
17. Go ahead and create your project and release directory for Capistrano to use.
mkdir /rails_apps/myapp
mkdir /rails_apps/myapp/releases

IMPORTANT! It is necessary to update your nginx configuration if you are using Capistrano.  Since cap uses the “current” directory and links to a release directory, your nginx config should change the “root” entry in the server block

open /opt/nginx/conf/nginx.conf and change the “root” entry to “root /rails_app/myapp/current/public;”  Then you can restart nginx like this:

sudo killall -9 nginx
sudo /opt/nginx/sbin/nginx
18. Capistrano Setup

Now you are ready to move on to Capistrano setup. I do all development locally on my Mac, commit the code with git and push it to my repository at github. In order to use Capistrano to deploy, you will need to “gem install capistrano” on your Mac (or windows box.. say it ain’t so!) and add 2 files to your Rails project. /myapp/Capfile and /myapp/config/deploy.rb. Here are my files:

Capfile

load 'deploy' if respond_to?(:namespace) # cap2 differentiator
Dir['vendor/plugins/*/recipes/*.rb'].each { |plugin| load(plugin) }

load 'config/deploy' # remove this line to skip loading any of the default tasks

deploy.rb – most of this config came from the passenger capistrano recipe.

set :application, "myapp"

#github stuff
set :repository,  "git@github.com:your_github_id/myapp.git"
set :scm, :git
set :scm_username, "your_github_id"
set :scm_passphrase, "your_github_passwd"

set :use_sudo,    false
set :deploy_to,   "/rails_apps/#{application}"

#server login
set :user, "app_user"
set :password, "server_password_here"

ssh_options[:forward_agent] = true

# will be different entries for app, web, db if you host them on different servers
server "123.456.12.34", :app, :web, :db, :primary => true

namespace :deploy do
  task :start, :roles => :app do
    run "touch #{current_release}/tmp/restart.txt"
  end

  task :stop, :roles => :app do
    # Do nothing.
  end

  desc "Restart Application"
  task :restart, :roles => :app do
    run "touch #{current_release}/tmp/restart.txt"
  end
end

Now you are ready to deploy. The whole point of using Capistrano is so you don’t have to login to your servers to push code, do restarts, etc.. So on your mac, you will run the “cap” commands for deployment.

This is a 3 step process.  Run these from the command line on your development box while in your rails app root directory (dir that contains Capfile):

  1. cap deploy:check   #this will check for dependencies
  2. cap deploy:setup  #this will create your shared directories.. log, pids, system
  3. cap deploy  #this will pull your code from github and put it in a new release directory, create a link to “/rails_apps/myapp/current” directory for that release and restart your passenger server

Now, take a look at your app on the server.  If you are lucky it will be running as expected, but I highly doubt it if you have gems that need to be installed.  Lets use bundler to get the necessary gems installed.  If you are Rails 3 savvy, you know that all your gem dependencies should be in /myapp/Gemfile, and that you can use Bundler (which is awesome BTW.. thnx wycats) to install them easily.

Passenger gives me a real pretty screen that says: “Could not find gem ‘mysql (= 2.8.1, runtime)’ in the gems available on this machine. (Bundler::GemNotFound)”

My Gemfile contains that gem, but it is not on my server.  So to get Bundler to install it, you will need to navigate over to your rails app root directory on the server. I mentioned earlier that you should not set up your rails app with the ‘root’ account on your linux box, and this is the problem that I ran into. When I installed with bundler, it put the bundled gems in /root/.bundle/…. and the web server could not access the gems, because passenger runs as ‘nobody’. If you run the server as ‘app_user’ or whatever you account is, then you should bundle install with the same account, so you dont have permission problems.

cd /rails_apps/myapp/current
bundle install  #no need for sudo here.  You want them to install in your user's home dir
19. Memcached Setup

Next on my list was getting memcached working. I use memcached as my cache store. In /myapp/config/environments/production.rb, I have the following line:

config.cache_store = :mem_cache_store

So passenger was complaining about not having memcached -> no such file to load — memcache

First I need to install memcached on the server. You can use a seperate server for memcached but you need to update the line in production.rb, to point to that server. It uses localhost by default.
In order to get memcached to work, you have to install libevent first

cd
wget http://www.monkey.org/~provos/libevent-1.4.13-stable.tar.gz
tar -xvf libevent-1.4.13-stable.tar.gz
cd libevent-1.4.13-stable
./configure && make
sudo make install
cd ..
wget http://memcached.googlecode.com/files/memcached-1.4.5.tar.gz
tar -xvf memcached-1.4.5.tar.gz
cd memcached-1.4.5
./configure && make
sudo make install
#you will get errors if you do not do the next 2 steps.  Create libevent config file, add a line to it, and then run ldconfig
sudo vi /etc/ld.so.conf.d/libevent-i386.conf  #create this file and add one line ->
                                                              # /usr/local/lib/
sudo /sbin/ldconfig
#start your memcached server up
sudo /usr/local/bin/memcached -u nobody &
#you should add this last command to /etc/rc.local so the memcached server starts if there is a reboot

Now your memcached server is running, but you still have to install the gem. Let’s add it to our Gemfile, git commit, & git push on our Mac, run “cap deploy” and then bundle install again on the server

#Gemfile located at myapp/Gemfile. on your dev box
group :production do
gem “memcache-client”
end

One note of caution here.. if you are already in /rails_apps/myapp/current, you need to cd again. If I remember correctly I ran into the problem of being in an old release directory. I guess when the link was update, my shell did not catch the update and was pointing current to the previous release directory.

cd /rails_apps/myapp/current
bundle install

You should have a working Rails app with memcached now. I did run into one gotcha when I was doing this. I had a legacy Rails app that I was upgrading and the following line was in environments/production.rb:

config.action_view.cache_template_loading = true

This line needs to be removed if you get the following error -> “undefined method `cache_template_loading=’ for ActionView::Base:Class”

Now open up your app in your browser and feel all the Rails 3 goodness! You are a rock star!

Hopefully YMDNV ;-)   Everything seems to be working so far on Rails 3 and I have a fairly complex app with quite a few plugins.  I think the hardest part about adopting Rails 3 is the fact that plugins are not ready.  I spent a good bit of my time troubleshooting and patching (yeah.. some monkey stuff) plugins.  You can read more about my upgrade experiences in this post.

Tags: , , , , ,