Resources for Getting Started with Ruby on Rails »
Created at: 16.11.2010 01:02, source: Engine Yard Blog, tagged: Uncategorized books classes community courses irc rails ruby Tutorials
Online Tutorials
Ruby Learning Official Ruby on Rails Guides Rails Tutorial Why's (Poignant) Guide [Thanks timinman from HN]Interactive Tutorials
Try Ruby Hackety Hack Ruby Koans BitNami [Thanks Daniel from comments] Rails for Zombies [Thanks Gregg from twitter]Books
Learn to Program Humble Little Ruby Book The Rails Way The Rails 3 Way [Thanks Raj from comments]Blogs
Ruby Inside Ruby Reflector Engine Yard Ruby on Rails Blog PlanetRubyOnRails [Thanks jim_h from HN]Screencasts
Railscasts PeepCode Ruby on Rails 3 Tutorial Lynda.com [Thanks eAlchemist from comments] Learning Rails [Thanks eAlchemist from comments] Learnivore [Thanks Thibaut from comments]Podcasts
Ruby on Rails Podcast The Ruby Show Teach Me To Code Ruby5 [Thanks EppO from comments] RubyPulse [Thanks pdelgallego from HN]Forums
Rails Forum StackOverflow Engine Yard Community SiteCommunity
Ruby Meetup Groups Ruby on Rails Community Confreaks [Thanks pdelgallego from HN] IRC Channels: #ruby, #ruby-lang, #rubyonrails, #jruby, #rubiniusCourses
Engine Yard University Blazing Cloud Courses Ruby Mendicant University Jumpstart Lab Courses [Thanks Jeff from twitter]more »
Mysql2 Error after upgrading an app to Rails 3 »
Created at: 28.09.2010 07:22, source: Hackido, tagged: ruby mysql linux rails mac
more »
Announcing RailsDeveloper »
Created at: 01.09.2010 20:01, source: Robby on Rails, tagged: Ruby on Rails ruby programming PLANET ARGON railsdeveloper rubyonrails rails
Earlier today… our team at Planet Argon launched a new site for the Ruby on Rails community. If you have a few spare minutes, I’d love it if you’d to head over and read the announcement on RailsDeveloper.
Enjoy!
more »
Pragmatic Polyglot Persistence with Rails »
Created at: 23.08.2010 12:50, source: Engine Yard Blog, tagged: Technology rails redis
class Friend < ActiveRecord::Base
belongs_to :user
belongs_to :contact, :class_name => "User", :foreign_key => "contact_id"
# user befriends contact
def self.befriend(user,contact)
relationship = find_by_user_id_and_contact_id(user.id,friend.id)
if relationship.nil?
transaction do
Friend.create(:user => user, :contact => contact)
end
end
end
end
class User < ActiveRecord::Base
has_many :friends, :dependent => :destroy
has_many :contacts, :through => :friends, :order => "created_at DESC", :dependent => :destroy
end
However, I have always felt that it's clumsy. What I really want to say is:
"Each user has a list of IDs that represent the people that they are friends with."
Sounds like a de-normalized list right?
h2. The Solution
Enter Redis. Redis is a key-value store similar to memcached but more flexible since lists, sets, ordered sets and strings can all be used as values. Thanks to its simple API, the problem I described is essentially an atomic operation in Redis. Redis has a great "set" implementation and allows you to do all of the things you would imagine a set to do: addition, subtraction, unique insertion, deletion, union, intersection, etc.
The operation will ultimately look like this:
SET = Redis.new
SET.set_add key, value
However, since we are working inside a Rails app, we need to make sure we have the right plumbing setup.
# Create a redis.rb in your initializers folder.
# Create a new Redis database for each of your needs.
In our case, we want to have a dataset that keeps track of a User's helpers (other users who are helping them) and a list of a User's friends (other users that the user is helping). Since we are going to be using these Redis objects throughout the codebase, I like to declare them as global variables in the redis.rb initializer file.
HELPERS = Redis.new(:db => 0)
HELPING = Redis.new(:db => 1)
Notice that I pass in the :db key so that we make sure HELPERS and HELPING will hold two different Redis objects. You can use redis-namespace gem if you want, but I find the default syntax from the redis-rb gem works well enough for my purposes.
Now that we have these global Redis objects at our disposal throughout the application, we can start using it in our Friend.befriend method.
class Friend < ActiveRecord::Base
belongs_to :user
belongs_to :contact, :class_name => "User", :foreign_key => "contact_id"
# user befriends contact
def self.befriend(user,contact)
begin
HELPERS.set_add contact.id, user.id
HELPING.set_add user.id, contact.id
rescue
RedisLogger.info "Redis Exception"
end
end
end
class User < ActiveRecord::Base
has_many :friends, :dependent => :destroy
has_many :contacts, :through => :friends, :order => "created_at DESC", :dependent => :destroy
end
However, this isn't the best solution right out of the gate. Using a NoSQL datastore has some drawbacks that aren't apparent in development mode but reveals its ugly face in production. If you are not careful, a simple restart of your Redis server can cause you to loose all your data. Managing your Redis data in production deserves it's own post, (coming soon) but for now, let's create a safer solution that you can gradually roll out as you become more comfortable with storing, backing up and using Redis datafiles.
class Friend < ActiveRecord::Base
belongs_to :user
belongs_to :contact, :class_name => "User", :foreign_key => "contact_id"
# user befriends contact
def self.befriend(user,contact)
relationship = find_by_user_id_and_contact_id(user.id,friend.id)
if relationship.nil?
transaction do
Friend.create(:user => user, :contact => contact)
end
add_to_denormalized_list(user,contact)
end
end
def self.add_to_denormalized_list(user,contact)
begin
HELPERS.set_add contact.id, user.id
HELPING.set_add user.id, contact.id
rescue e
RedisLogger.info "Redis Exception"
end
end
end
class User < ActiveRecord::Base
has_many :friends, :dependent => :destroy
has_many :contacts, :through => :friends, :order => "created_at DESC", :dependent => :destroy
end
The strategy is simple, mirror the MySQL data in Redis. By adding a call to add_to_denormalized_list, we mirror the ActiveRecord call using the simple and elegant Redis set syntax discussed above. As you and your team get more practice and become more comfortable using Redis in production, you can start writing more to the denormalized list, eventually moving this part of your application away from ActiveRecord and MySQL to Redis. You could do this manually or you can use James Golick's recently released gem called Rollout that uses, you guessed it, Redis, to programatically rollout features to users.
Like anything else you code, testing and benchmarking this process in production is crucial to make sure you are saving time and cycles. It might seem like a waste to duplicate your data in Redis, but you are a pragmatic polyglot persistence developer right? You want to explore the NoSQL space while making sure that a little mistake or misunderstanding doesn't sink your ship. Give something like this a try, it doesn't get any more pragmatic. When do you try it or come up with something new, let me and everyone else know about it.
Thanks for reading.more »
Rails 3 Internals: Railtie & Creating Plugins »
Created at: 04.08.2010 19:58, source: igvita.com, tagged: Ruby on Rails plugin rails railtie
With the official Rails 3 release on the horizon, all of the edge features we have been hearing about for over a year are about to become the new standard, and it has definitely been worth the wait. One of the primary goals of the "big refactor" has been to modularize Rails to allow other frameworks to easily extend or entirely replace any of the previously "critical" components (ActiveRecord, ActionMailer, etc). At the centre of all this, is the new Railtie logic, which pieces all of these modules together.
Getting started with Railtie
The documentation for Railtie is a great place to get started, but the interesting observation is that each of the major Rails components (Action Mailer/Controller/View/Record) is itself a Railtie, and Rails as you know it is simply pieced together by requiring all of the independent components. Even better, if your plugin or gem needs to hook into the Rails initialization process, all you need to do is inherit from Railtie and you are ready to go!
So how does Railtie know to call your classes and initializers? Railtie defines a self.inherited method, which is called anytime a subclass of Railtie is created, and stashes a reference to this class in a @subclasses variable. From there, the framework can simply call Railtie.subclasses and perform all the initialization as usual - a clever use of the Ruby object model.
Creating a Rails 3 plugin: 0-60
As a result of the refactor, creating Rails 3 plugins is at least several orders of magnitude simpler. In fact, as a simple exercise, lets create a custom notification plugin to print all of the internal Rails logging by also hooking into the new Rails::Notification API:
module NewPlugin # namespace our plugin and inherit from Rails::Railtie # to get our plugin into the initialization process class Railtie < Rails::Railtie # configure our plugin on boot. other extension points such # as configuration, rake tasks, etc, are also available initializer "newplugin.initialize" do |app| # subscribe to all rails notifications: controllers, AR, etc. ActiveSupport::Notifications.subscribe do |*args| event = ActiveSupport::Notifications::Event.new(*args) puts "Got notification: #{event.inspect}" end end end end
Believe it or not, that is a fully functional Rails 3 plugin, in 10 lines of code. Simply drop this file into your load path and require it in your application. In fact, you can bundle this file into a gem, ship it to Gemcutter and with the help of Bundler, all your users have to do is specify "gem 'ournew-plugin'" in their Gemfile, and the rest is taken care of. With a little more imagination, and fun, we can extend our example above into a 'slowgrowl' plugin, which will - you guessed it - growl at the developer anytime it detects a slow code path in your app! Hat tip to Gavin Stark for the idea.
Getting started with Rails 3
Railtie while an important piece of Rails 3, is hardly the only component worth looking into. Also read up on the changes in ActiveRecord, the new router, watch the summary screencasts on the Rails site, and make sure to check out one of the many great Railscasts on the topic by Ryan Bates. It has been worth the wait, Rails 3 is easily head and shoulders above the competition.
more »
