Topic: Re: rewriting relationship methods

I guess I'll approach this in baby steps and who knows maybe I'll get the answers to my overall questions:

Say I have a Project model with a has_many relationship to a Milestone Model with a has_many relationship to a Deed model.

The has_many gives me the method @project.milestones.  And of course by doing something like:

for @milestone in @project.milestones
  @milestone.deeds
end

I can access all the deeds that belong to the milestones.  But now I'd like to select only the milestones that have an attribute (field in DB) called complete set to 1, and also order by a field called name.  How can I have an iterable list returned that still treats each item as an instance of a model?  I've tried writing instance methods in the model using find_by_sql and though the returned items have the fields of the table as attributes they don't have any of the instance methods i've defined in their model.

Hope that makes sense.

If art interprets our dreams, the computer executes them in the guise of programs.

-SICP (Abelson, Sussman)

Re: Re: rewriting relationship methods

So I can do that with something like:

for @milestone in @project.milestones.find(:all, :order => "name", :conditions => "complete = 1")
  @milestone.deeds
end

But let's say I'm going to need to do that all the time and it's even more complex, how would I overwrite @project.milestones and still be able to say @milestone.deeds?  This makes no sense save a recursive function, but what would be the equivilant:
def milestones
  return self.milestones.find(:all, :order => "name", :conditions => "complete = 1")
end

If art interprets our dreams, the computer executes them in the guise of programs.

-SICP (Abelson, Sussman)

Re: Re: rewriting relationship methods

I think you're almost there. Instead of overwriting the milestones method, just create a new method called completed_milestones:

class Project < ActiveRecord::Base
  def completed_milestones
    milestones.find(:all, :order => "name", :conditions => "complete = 1")
  end
end

And then in your view:

for milestone in @project.completed_milestones
  milestone.deeds
end

You should still be able to call milestone.deeds and any other methods.

Alternatively, if you want milestones to always return the completed ones, you can set the condition when you set has_many:

class Project < ActiveRecord::Base
  has_many :milestones, :conditions => 'complete=1', :order => 'name'
end

Railscasts - Free Ruby on Rails Screencasts

Re: Re: rewriting relationship methods

I knew I could write a new one, I just really wanted to overwrite the old one because rails has me so accustomed to readable programs.  The way that things are set up in what I'm really doing is the name that makes the most sense for the method has already been taken by active record relationships.  Also, I've some other situations where I'd really like to pass back model instances off a find_by_sql statement.  Is there any way to do that?

If art interprets our dreams, the computer executes them in the guise of programs.

-SICP (Abelson, Sussman)

Re: Re: rewriting relationship methods

circuitshaman wrote:

I knew I could write a new one, I just really wanted to overwrite the old one because rails has me so accustomed to readable programs. The way that things are set up in what I'm really doing is the name that makes the most sense for the method has already been taken by active record relationships.

Did you see the alternative suggestion at the bottom of my post? Try that if you want all project milestones to be complete.

circuitshaman wrote:

Also, I've some other situations where I'd really like to pass back model instances off a find_by_sql statement.  Is there any way to do that?

If you do something like this, it should return instances of the Milestone model:

@milestones = Milestone.find_by_sql "SELECT * FROM milestones"

Just make sure you return all of the columns in the milestones table, or else the milestone instances will not have access to that data.

Last edited by ryanb (2006-08-30 13:40:44)

Railscasts - Free Ruby on Rails Screencasts

Re: Re: rewriting relationship methods

Sorry about that.  That last post is great.  If I select a single tables fields but using a from statement with multiple tables and linking will it still return instance variables?

@resources = Project.find_by_sql("Select users.* from users, projects, resources WHERE projects.id = resources.project_id and users.id = resources.user_id")

...as a crude example

Last edited by circuitshaman (2006-08-30 13:52:35)

If art interprets our dreams, the computer executes them in the guise of programs.

-SICP (Abelson, Sussman)

Re: Re: rewriting relationship methods

You need to make sure the select statement returns the columns of the model you are calling find_by_sql on. In your example, the select statement is returning the columns from the users table, not the columns from projects table.

Railscasts - Free Ruby on Rails Screencasts

Re: Re: rewriting relationship methods

GENIUS!  Oh that makes excellent sense.  Rails is some hot stuff.  Thanks a lot for your help ryanb.

If art interprets our dreams, the computer executes them in the guise of programs.

-SICP (Abelson, Sussman)