ruby-on-railsnested-attributesaccepts-nested-attributes

Rails 4 Accept nested attributes with has_one association


I have a question about Rails Nested Attributes. I'm using Rails 4 and have this model:

model Location
 has_one parking_photo
 has_many cod_photos
 accepts_nested_attributes_for :parking_photo
 accepts_nested_attributes_for :cod_photos
end

When I use for example: Location.find(100).update(cod_photo_ids: [1,2,3]) it works.

But Location.find(100).update(parking_photo_id: 1) doesn't works.

I don't know what difference between nested attributes has_one and has_many.

Or do we have any solution for my case, when I already have child object and want to link the parent to the child and don't want to use child update.

Thank you.


Solution

  • The problem has nothing to do with nested attributes. In fact you're not even using nested attributes at all in these examples.

    In this example:

    Location.find(100).update(cod_photo_ids: [1,2,3])
    

    This will work even if you comment out accepts_nested_attributes_for :cod_photos as the cod_photo_ids= setter is created by has_many :cod_photos.

    In the other example you're using has_one where you should be using belongs_to or are just generally confused about how you should be modeling the association. has_one places the foreign key on the parking_photos table.

    If you want to place the parking_photo_id on the locations table you would use belongs_to:

    class Location < ActiveRecord::Base
      belongs_to :parking_photo
      # ...
    end
    
    class ParkingPhoto < ActiveRecord::Base
      has_one :location # references  locations.parking_photo_id
    end 
    

    Of course you also need a migration to actually add the locations.parking_photo_id column. I would really suggest you forget about nested attributes for the moment and just figure out the basics of how assocations work in Rails.

    If you really want to have the inverse relationship and put location_id on parking_photos you would set it up like so:

    class Location < ActiveRecord::Base
      has_one :parking_photo
      # ...
    end
    
    class ParkingPhoto < ActiveRecord::Base
      belongs_to :location
      validates_uniqueness_of :location_id
    end 
    

    And you could reassign a photo by:

    Location.find(100).parking_photo.update(location_id: 1)