Tim, the Enchanter

What manner of man are you that can summon up code without C# or Java?

Friday, October 3, 2008

 

My support for proposition #8

This post was originally on how to change your default search engine to Yahoo, because of my disappointment in Google on taking an official position on proposition #8.

After a day, I’ve decided that joining a boycott on Google search would not be an effective way to promote traditional families. After all, Google still remains neutral on the content hosted by it’s many wonderful services.

Still, my position on defending marriage as being defined between man and woman remains in effect. Strong, functional families are the backbone for any society. With out them, the world crumbles.


If you wish to make Safari use yahoo to search, here’s the script to do it:

  cd /Applications/Safari.app/Contents/MacOS/ && 
    [ ! -f Safari.google ] && 
    sed -i .google 's|http://%@.google.com/%@?q=%@&ie=UTF-8&oe=UTF-8|http://search.yahoo.com/bin/search?%@%@=0\&p=%@|' Safari

Just open up a terminal and paste the whole command. It’ll create a backup, Safari.google. If you want to go back, you can undo it with this:

  cd /Applications/Safari.app/Contents/MacOS/ && mv Safari.google Safari

Thursday, October 2, 2008

 

How to has_many :through a has_many :through

So, I’ve got 3 models:

  User -< UserConversation >- Conversation -< Message

  (where -< is has many, >- is belongs to, ... etc)

I wanted, in this application, to be able to filter to all messages for a given user.

  User#messages.find(message_id)

So, naturally, I first reached for this:

  class User < ActiveRecord::Base
    ...
    has_many :user_conversations
    has_many :conversations, :through => :user_conversations
    has_many :messages, :through => :conversations
  end 

  class UserConversation < ActiveRecord::Base
    belongs_to :user
    belongs_to :conversation
  end

  class Conversation < ActiveRecord::Base
    has_many :user_conversations, :dependent => :destroy
    has_many :messages, :dependent => :destroy
  end

  class Message < ActiveRecord::Base
    belongs_to :conversation
  end

Which… is completly WRONG and yields results like the following:


  >> User.first.messages

  ActiveRecord::StatementInvalid: SQLite3::SQLException: no such
  column: conversations.user_id: SELECT "messages".* FROM "messages"
  INNER JOIN conversations ON messages.conversation_id =
  conversations.id    WHERE (("conversations".user_id = 1)) 

So, apparently ActiveRecord doesn’t support joins like that. Sure, I could resort to manually specifying the finder_sql in the join and skip the has_many :through business, but then I’d lose the that cool ability to apply additional scopes after this – major FAIL.

So, I came up with a clever way to get around it.

  class User < ActiveRecord::Base
    ...
    has_many :user_conversations
    has_many :conversations, :through => :user_conversations

    def messages
      Message.for_user(self)
    end
  end

  class Message < ActiveRecord::Base
    belongs_to :conversation
    
    named_scope :for_user, lambda { |user| user = user.id if user.is_a?(User); { :joins => {:conversation => :user_conversations}, :conditions => ["user_conversations.user_id = ?", user]}}
  end

And… now we can do things like:

  user.messages.find(1)
  user.messages.matching_subject("boogy man")

etc., etc. Hurray for named_scope. So.. there's still a few issues. Namely, it's not REALLY an association - no "create" or "build" methods.

Dear web: what do think about this? Got a better way to implement the above scenario?

Labels:


Archives

March 2008   April 2008   May 2008   June 2008   July 2008   August 2008   October 2008   November 2008   February 2009   June 2009   December 2009   January 2010   February 2010   May 2010   June 2010   November 2010  

This page is powered by Blogger. Isn't yours?

Subscribe to Posts [Atom]