Domanda

I have three models :

class LevelTwoArea < ActiveRecord::Base
  has_many :places, dependent: :restrict
end

class Place < ActiveRecord::Base
  belongs_to :level_two_area
  has_many   :producers, dependent: :restrict

  validates_presence_of :level_two_area_id
end

class Producer < ActiveRecord::Base
  belongs_to :place

  validates_presence_of :place_id
end

I also have a controller with an ActiveScaffold per model.

Problem is, when i want to create a new Place, the scaffold spits an error to the log :

ActiveScaffold::ReverseAssociationRequired (Association producers: In order 
to support :has_one and :has_many where the parent record is new and the child 
record(s) validate the presence of the parent, ActiveScaffold requires the 
reverse association (the belongs_to).)

I don't understand why...

Notice that :

  • Other similar scaffolds do work
  • i can create records and use associations in the console :

    >> Place.new name: 'PONVOGO', level_two_area_id: 10144
    => #<Place id: nil, name: "PONVOGO", latitude: nil, longitude: nil, producers_count: nil, level_two_area_id: 10144, created_at: nil, updated_at: nil, marker: nil>
    >> _.save
    => true
    >> Producer.first.place.producers
    => [#<Producer id: 1, name: "KOFFI YAO GREGOIRE", place_id: 43, created_at: nil, updated_at: nil>]
    
  • The problem disappears when i remove the has_many :producers, though the association macros look perfectly normal

  • The problem won't disappear if i remove the dependent: :restrict option
  • i have a producers_census column on my Place model, i suspect this to mess things up but would like to have confirmation before doing heavy refactoring. Removing this column from the scaffold won't fix the problem.

fields on the places table :

Column             |            Type             |                                  
--------------------------------------------------
 id                | integer                     | non NULL (PK)       
 name              | character varying(50)       | non NULL
 latitude          | double precision            | 
 longitude         | double precision            | 
 producers_census  | integer                     | 
 level_two_area_id | integer                     | non NULL (FK)
 created_at        | timestamp without time zone | 
 updated_at        | timestamp without time zone | 
 marker            | geometry                    | 

my entire PlacesController :

class PlacesController < ApplicationController
  active_scaffold :place do |conf|
    conf.columns =  :name,
                    :level_two_area,
                    :latitude,
                    :longitude,
                    :producers_census
    export.columns.add  :id, 
                        :level_two_area_id

    [:latitude, :longitude].each {|column| conf.columns[column].options[:format] = "%.14f" }

    [               
      create,
      update,
      delete,
      batch_update 
    ].each do |action|
       action.link.security_method = :can_see_link?
    end
    batch_destroy.link.each {|sublink| sublink.security_method = :can_see_link? }

  end
end 

i'm on rails (3.0.5) / active_scaffold_vho (3.0.17) / ruby (1.9.2p180)

È stato utile?

Soluzione

While I've never seen this ActiveScaffold exception before, I think this is what's going on:

The reverse association is set up with the :inverse_of option, and its effects will be visible only while the records are unsaved. This is why you don't see it in your console experiment.

Try this:

place = Place.new
=> #<Place ...>
producer = place.producers.build
=> #<Producer ...>

producer.place
=> nil
place.producers.first.place
=> nil

These records will fail your validation, when built entirely in memory. If you never build a place and a producer at the same time, then you don't have to worry about this. If you do, however, then your validation rule also should be written to check for the existence of :place (i.e. the object), not :place_id:

validates_presence_of :place

I don't know which build/creation mechanism ActiveScaffold uses, but I would guess that if they throw this exception, that they may build things in memory.

So, to fix this, try:

class Producer < ActiveRecord::Base
  belongs_to :place, inverse_of: producers

  validates_presence_of :place
end

class Place < ActiveRecord::Base
  has_many :producers, inverse_of: place
end

Note: ActiveRecord used to not support :inverse_of on the has_many side and that limitation used to be commented in the source. As of Rails 3.1, this seems fixed. If you amend your classes with :inverse_of as shown, then the console experiment with in-memory objects should return the associated object.

You may want to review the Rails API docs on bi-directional associations

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top