Silence is Foo Mental notes on Ruby/Git/Rails/Flex

30Aug/100

Mimicking Rails 3’s ActiveRecord query interface in Rails 2.x

NOTICE: This is only for educational and fun purposes, nothing else. I'm not trying to say that you'll get all the pros of the new query interface in Rails 2.x, it isn't even close.

The first time I used the new ActiveRecord query interface (Rails 3) I started to get boring with the one in Rails 2.x, I can't do anything, I have to use the old query interface since converting my projects from Rails 2 to Rails 3 is not an option, so I thought to make a sort of placebo, just for fun, just to be used in my local console, and here is.

module FakeActiveRecord3Methods
  def self.included(base)
    base.class_eval do
      %w/select group order limit offset joins having/.each do |method|
        named_scope method.to_sym, lambda { |arg| { method.to_sym => arg } }
      end

      named_scope :where, lambda { |arg| { :conditions => arg } }
      named_scope :includes, lambda { |arg| { :include => arg } }
    end
  end
end

Click here to see a Gist in GitHub

I used named scopes because they are chainable, if I would have added instance methods to ActiveRecord::Base it would haven't worked as I want to, maybe there's a way to make it work that way, but this was a 5-minutes module, I didn't want to spent too much time on it.

well, I have to say I don't use this module in production servers, only locally in development mode. This is how I configure my development environment to use it:

In my environment/development.rb

config.after_initialize do
  [User, And, All, The, Models, You, Want].each do |model|
    model.class_eval do
      include FakeActiveRecord3Methods
    end
  end
end

Click here to see a Gist in GitHub

I add the models I use the most, if I need to use the FakeActiveRecord3Methods module in other model I include it in the console. To make this even easier I added to my ~/.irbrc the following code:

class Class
    public :include
end

It allows us to include a module this way:

Profile.include FakeActiveRecord3Methods

otherwise Ruby will throw an exception saying we're trying to access a private method.

It might seem cumbersome to make all of this but it isn't that hard.

It's a shame I won't be able to prove that FakeActiveRecord3Methods works in most of the cases but you can test with the examples shown in Rails Guides: Active Record Querying.

Here are some queries using this module anyways. I think all of them are self-explanatory.

User.select("id, email").limit(2)
=> [#<User id: 1, email: "e@mail.com">, #<User id: 2, email: "bar@foo.com">]
User.select("id, email").where(["created_at > ?", 1.month.ago]).order("email DESC").limit(1)
=> [#<User id: 5, email: "foo@bar.com">
User.limit(5)

User.select(:id)

User.select(:id).limit(10).offset(100)

User.order :created_at

Joins

users = User.select("users.id, profiles.company").joins(:profile)
users.first.company # => Foo Company

users.first.profile.company # => Foo Company

Includes

users = User.limit(10)
users.first.name # => Foo
users.first.profile.company # => it will query the database

users = User.includes(:profile).limit(10) # it will bring the profile as well
users.first.profile.company # it won't query the database

Of course, you should be aware that in named scopes the order really matters, be careful and remember, in Rails 3, the where, select, group, order, limit, offset, joins and includes returns an instance of ActiveRecord::Relation which is not the case in the FakeActiveRecord3Methods module, it returns an instance of ActiveRecord::NamedScope::Scope and that's because named scopes returns an instance of such class.

By the way, if you want to read the Rails 2's ActiveRecord Query Interface, you can do so clicking here

Thanks for reading.

Filed under: rails Leave a comment
27Aug/103

MUSh, a multi-service URL shortener in Ruby

I have to tell the truth, I'm really lazy, if there is a way to avoid to do something I will do so.

What about avoiding to open a browser or create a new tab and click a bookmark or type the address of a URL shortener service when I want to shorten a URL? If I have an opened terminal with IRb and Bash almost the whole day, why don't use it to shorten URLs?

Using the most pure principles of LDD (Laziness-Driven Development) I've created a gem called MUSh, a Multi-service URL Shortener, hence the name.

Yes, I know there are thousands of API wrappers in Ruby for bit.ly, etc. but most of them are fully-featured API wrappers and I didn't want all of those features, I just wanted to shorten URLs, that's it, well, I wanted command-line utilities as well, but I didn't find them in any existing gem.

I've been using MUSh for almost a month now, and it really helps me, that's why I decided to release it as a gem, if you want to install it just do it this way:

$ sudo gem install mush

It currently supports bit.ly, is.gd and u.nu services and it have one command-line utility per service:

$ isgd foo.raflabs.com

$ unu foo.raflabs.com

$ bitly -l your_login -k your_apikey -u foo.raflabs.com

Hum, the last command doesn't help that much. I know. MUSh currently doesn't support storing your credentials so I use an alias.

In your ~/.bash_profile or ~/.bashrc:

alias bitly='bitly -l your_login -k your_apikey'

after adding your alias issue the following command to refresh your terminal or close it an open another one:

$ source ~/.bash_profile (or whatever is your file called)

and now you'll be able to use the bitly command without specifying your credentials, even without specifying the -u option.

$ bitly foo.raflabs.com

If you're in a Mac and want to copy the shortened URL in one step, just use the pbcopy command:

$ bitly foo.raflabs.com | pbcopy

Then paste it with Cmd-V or with the pbpaste command.

MUSh was made in Ruby, so you can use it in your Ruby applications as well.

Bit.ly

bitly = Mush::Services::Bitly.new

bitly.login = "your_login"
bitly.apikey = "your_apikey"

bitly.shorten "http://foo.raflabs.com" # => http://bit.ly/bJO5IH

Is.gd

isgd = Mush::Services::IsGd.new

isgd.shorten "http://foo.raflabs.com" # => http://is.gd/eFZXc

u.nu

unu = Mush::Services::Unu.new

unu.shorten "http://foo.raflabs.com" # => http://u.nu/3hsje

Besides, If you want to shorten a URL in your Ruby or Rails console in a fast way add the following to your ~/.irbrc:

require 'mush'

def by(url)
  bitly = Mush::Services::Bitly.new
  bitly.login = "your_login"
  bitly.apikey = "your_apikey"

  bitly.shorten url
end

def is(url)
  Mush::Services::IsGd.new.shorten url
end

def un(url)
  Mush::Services::Unu.new.shorten url
end

An use it like this


by "google.com"

is "google.com"

un "google.com"

It's a nice set of shortcuts, I'd say.

Again, if you're in a Mac and want to copy the shortened URL in one step, just use my pasteboaRb gem:

$ sudo gem install pasteboaRb

Basically, pasteboaRb adds to_pb and paste methods to the Object class.

is("foo.raflabs.com").to_pb # => http://is.gd/eFZXc

Then paste it in any Mac application with Cmd-V, in the Terminal with the pbpaste command or in a Ruby terminal with the paste method.

paste # => http://is.gd/eFZXc

Finally, why supporting 3 services? it depends on the size you want, If you want the shortest url and you don't care about statistics use u.nu, if you want to see statistics of your shorten URLs and you don't mind to have 1 or 2 extra characters use bit.ly or is.gd.

To see statistics just add a + or - sign to the URL.

http://bit.ly/bJO5IH+
http://is.gd/eFZXc-

Thanks for reading.

Filed under: ruby 3 Comments