undefined method `target' in Rails associations (1.2)

I'm having trouble with one of my Rails model associations. They seem
simple enough, I have 99% of them working. But in one of them, when I
try to access a foreign key record, I get:

   undefined method `target' for #<Environment:0xb766c70c>

   vendor/rails/activerecord/lib/active_record/base.rb:1848:in
`method_missing'
   vendor/rails/activerecord/lib/active_record/associations.rb:891:in
`environment'
   app/models/revision.rb:154:in `start'
   app/controllers/revisions_controller.rb:9:in `start'

Has anyone seen this? My associations are:

   class Revision < ActiveRecord::Base
        belongs_to :environment
        belongs_to :source_revision,
             :class_name => 'Revision',
             :foreign_key => 'source_revision_id'
   end

   class Environment < ActiveRecord::Base
       belongs_to :layout
       belongs_to :life_cycle
       has_many :revisions
       has_many :titles, :through => :environment_titles
   end

I've tried many different variations, singular/plural, etc. BTW, the
'source_revision' one works fine (I tried specifying everything to the
environment belongs_to but it didn't matter)

Here's my tables, any clues? I'm REALLY stuck...

desc revisions;

Name Null? Type
----------------------------------------- --------

Nate wrote:

   undefined method `target' for #<Environment:0xb766c70c>

   vendor/rails/activerecord/lib/active_record/base.rb:1848:in
`method_missing'
   vendor/rails/activerecord/lib/active_record/associations.rb:891:in
`environment'
   app/models/revision.rb:154:in `start'
   app/controllers/revisions_controller.rb:9:in `start'

Has anyone seen this? My associations are:

   class Revision < ActiveRecord::Base
        belongs_to :environment
        belongs_to :source_revision,
             :class_name => 'Revision',
             :foreign_key => 'source_revision_id'
   end

In your Revision model are you making any assignments to an @environment
instance variable, or have you defined an "environment" attr_accessor?
If so, rename to avoid conflict with the belongs_to.

Thanks - that's exactly what it was. Deeply nested private method
(written by somebody else :-).

Cheers,
Nate

Mark Reginald James wrote:

Nate wrote:

   class Revision < ActiveRecord::Base
        belongs_to :environment
        belongs_to :source_revision,
             :class_name => 'Revision',
             :foreign_key => 'source_revision_id'
   end

In your Revision model are you making any assignments to an @environment
instance variable, or have you defined an "environment" attr_accessor?
If so, rename to avoid conflict with the belongs_to.

--
We develop, watch us RoR, in numbers too big to ignore.

Is there a way to do this and have it use the association? I need to
override the assoc= method of a model to make sure the assignment
matches some predefined criteria. However, if I try to assign via
@assoc= I get the error message about an undefined target, and if I use
self.assoc= I wind up in an endless recursion until a stack overflow
occurs.

class Project < ActiveRecord::Base
  belongs_to :status, :class_name => "ProjectStatus",
    :foreign_key => 'status_code'

  # Updates the current project's status unless the current
  # status is greater than the new status. Status' are compared
  # using ProjectStatus::compare_status method The
  # new_project_status argument should be a ProjectStatus record
  # (i.e. ProjectStatus::SOME_STATUS)
  def status= (new_project_status, override = false)
    puts "Current status = #{@status}" #Debugging
    if override or @status < new_project_status
      puts "New status = #{new_project_status}" #Debugging
      @status = new_project_status
    else
      puts "No change in status" #Debugging
    end
  end
end

class ProjectStatus < ActiveRecord::Base
  has_many :project, :foreign_key => "status_code"

  def > (status); compare_status(status, ">"); end
  def >= (status); compare_status(status, ">="); end
  def < (status); compare_status(status, "<"); end
  def <= (status); compare_status(status, "<="); end

  def self.find_by_code (code)
    ProjectStatus.find(:first, :conditions => ['code = ?', code])
  end

  def to_s; self.status; end
  def to_i; self.id; end

  # Setup some shortcuts i.e. ProjectStatus::SOME_STATUS
  # will return the status record for that code
  def self.const_missing(sym)
    if s = ProjectStatus.find_by_code(sym.to_s)
      s
    else
      super
    end
  end

private

  def compare_status (status, op)
    eval self.order.to_s + op + status.order.to_s
  end
end

Mark Reginald James wrote:

Nate wrote:

  class Revision < ActiveRecord::Base
       belongs_to :environment
       belongs_to :source_revision,
            :class_name => 'Revision',
            :foreign_key => 'source_revision_id'
  end

In your Revision model are you making any assignments to an
@environment
instance variable, or have you defined an "environment"
attr_accessor?
If so, rename to avoid conflict with the belongs_to.

--
We develop, watch us RoR, in numbers too big to ignore.

Is there a way to do this and have it use the association? I need to
override the assoc= method of a model to make sure the assignment
matches some predefined criteria. However, if I try to assign via
@assoc= I get the error message about an undefined target, and if I
use
self.assoc= I wind up in an endless recursion until a stack overflow
occurs.

class Project < ActiveRecord::Base
belongs_to :status, :class_name => "ProjectStatus",
   :foreign_key => 'status_code'

# Updates the current project's status unless the current
# status is greater than the new status. Status' are compared
# using ProjectStatus::compare_status method The
# new_project_status argument should be a ProjectStatus record
# (i.e. ProjectStatus::SOME_STATUS)
def status= (new_project_status, override = false)
   puts "Current status = #{@status}" #Debugging
   if override or @status < new_project_status
     puts "New status = #{new_project_status}" #Debugging
     @status = new_project_status
   else
     puts "No change in status" #Debugging
   end
end
end

@status needs to be an association proxy, not the raw ProjectStatus
object. easiest way out is problably to alias_method the old status=
method so that you can call it easily from your status= method.

Fred

Frederick Cheung wrote:

@status needs to be an association proxy, not the raw ProjectStatus
object. easiest way out is problably to alias_method the old status=
method so that you can call it easily from your status= method.

Fred

Doesn't alias_method and alias_method_chain only work from within a
module? This is in an ActiveRecord class.

Frederick Cheung wrote:

> @status needs to be an association proxy, not the raw ProjectStatus
> object. easiest way out is problably to alias_method the old status=
> method so that you can call it easily from your status= method.

> Fred

Doesn't alias_method and alias_method_chain only work from within a
module? This is in an ActiveRecord class.

Classes are modules (in that Class is a subclass of Module) and there
is nothing special about ActiveRecord classes in that respect.

Fred

Frederick Cheung wrote:

Classes are modules (in that Class is a subclass of Module) and there
is nothing special about ActiveRecord classes in that respect.

Fred

Oh, OK. I swear I had trouble using alias_method in a class once, but
I'll give it another go.

Thanks!