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!