Archive for the 'Ruby on Rails' Category

Posted on March 30, 2006 at 9:45 pm

It looks like edge Rails revision 4007 breaks has_many :through associations if the association name does not correspond to the associated model. Before today, you could use :class_name to clear things up:

has_many :members, :through => :memberships, :class_name => "User"

That will now throw a nice descriptive error:

ActionView::TemplateError: Could not find the source association(s)
:member or :members in model Membership.  Try 'has_many :members,
:through => :memberships, :source => '.  Is it one of :user or :group?

You now need to specify the target model with :source:

has_many :members, :through => :memberships, :source => :user

I would just like to add that the world needs more error messages like the one above. Not only does it give you the correct syntax to use, but even tells you the two valid options for :source based on the real data!

Posted on March 21, 2006 at 6:21 pm

One of the new features being introduced in Rails 1.1 is ActiveRecord#with_scope. The with_scope functionality lets you wrapper a bunch of calls to Model#find or Model#create with a particular set of conditions. These conditions will always be used, regardless of what additional conditions you call Model#find with. If you want to know more about with_scope you might want to read the author’s article on how it works.

Rails includes the base with_scope and with_exclusive scope functionality, but there is a plugin called scoped_access that gives you a few nice tools to make life easier. The article I mentioned about tells you how to get a hold of it.

I’m using ScopedAccess::Filter in Callbx to enforce different types of security. For example, a user should never be able to see tickets from groups that he does not belong to. Normally I would have to write the conditions to restrict access on every action in the controller. Using a ScopedAccess::Filter I can set the scope for Ticket.find on the entire controller. This frees me to concentrate on the functionality for each action, rather than having to be concerned with the access control while coding the rest of the controller.

class TicketsController < ApplicationController

  # limit the scope on all calls to Ticket.find in this controller
  around_filter ScopedAccess::Filter.new(Ticket, :group_conditions)

  def list
    @ticket = Ticket.find(:all, :conditions => "status_code_id < 10")
  end

  protected

  # only show tickets from groups that the user is a member of
  def group_conditions
    conditions = []
    session[:user].groups.each do |group|
      conditions << "group_id = '#{group.id}'"
    end
    return :find => {:conditions => "(#{conditions.join(' OR ')})"}
  end

end

Assuming that the logged in user belongs to groups 5 and 17, the SQL generated on that Ticket.find in the list method would be something like:

SELECT * FROM `tickets` WHERE status_code_id < ‘10′ AND (group_id = ‘5′ OR group_id = ‘17′)

Posted on March 2, 2006 at 12:56 am

Lots of stuff to catch up on, so I’ll skip the niceties.

  • The changes in the Rails subversion repository have been coming fast and furious for the last couple of days. I usually like running on the edge, but today I had to stay locked to a previous version (3725) in order to keep working. Is this the final push to 1.1?
  • I ordered my new MacBook Pro yesterday. Dual core, 2GB of RAM, and the 100GB 7200rpm drive. Feel it.
  • Why the lucky stiff’s spectacular example of mentat logic has been integrated into Rails. I’m using it to do full renders in the new RJS templates:
    p = Proc.new { render_as_string :template => "/users/details" }; page.replace_html "user_details", p.bind(@controller).call
  • Last thursday I decided to try a vegatarian diet for 30 days. If it works out, I’ll stick with it for a while longer. If I don’t like it I’ll switch back. Tomorrow will be a full week and I’m very surprised that it’s been so easy to switch. I’ve considered making the switch for several months now, but always thought that I’d have a really hard time find things to eat. Not so, and I’ve actually lost 6 pounds this week to boot. This is very surprising because I’ve been unable to lose more than 2 pounds for over a year now, no matter what I’ve tried. I’m at 224 lbs today. My goal is 200 and then I’ll re-evaluate.
  • I’m no longer training for the San Diego marathon. I’m just not going to be able to make it at the pace my training is progressing. I’m still running 4 days a week and am planning on running the Portland Marathon in October.
  • Did I mention that I’ll be in Chicago for RailsConf 2006 in June?
  • I’ll also be at OSCON again this year, but probably only for the one day Ruby track. It’s too damn expensive to go for the whole thing.
Posted on February 14, 2006 at 9:43 pm

Have you ever wanted to pass a block to an ActiveRecord model in order to pre-filter results?

module ActiveRecord
  class Base
    class < < self
      alias_method :find_without_filter, :find
      def find(*args)
        records = find_without_filter(*args)
        if block_given?
          filtered = []
          records.each do |record|
            filtered << record if yield(record)
          end
          filtered
        else
          records
        end
      end
    end
  end
end

This is a quick and dirty hack of a plugin, but it does the trick. I’m far from satisfied though. Soliciting opinions from those in the know. Email me.

Posted on February 10, 2006 at 6:18 pm

I didn’t have to wait long for assurance_Why is putting (pudding?) on one of his “performances” at RubyConf 2006. Via Loudthinking.