I currently a polymorphic association set up like this
class Reading < ApplicationRecord
has_one :audio, as: :audioable
accepts_nested_attributes_for :audio
end
class Audio < ApplicationRecord
belongs_to :audioable, polymorphic: true
end
In my RSPEC test, I have this set up
#reading = attributes_for(:reading, creator: #user, body: "who let the dogs out? Must be me\n\nMeMeMe")
#reading[:audio_attributes] = attributes_for(:audio)
However, I get the following errors when posting this #reading to the reading#create controller
{:errors=>{:"audio.audioable"=>["must exist"]}}
For non-polymorphic associations I've gotten it to create both the parent and nested resources using inverse_of but I'm not sure how to do it for polymorphic associations.
inverse_of can't be used for polymorphic associations, have you looked at Single Table Inheritance it could be a good solution depending of what you are trying to achieve
Related
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.
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)
I have an issue creating a new record with nested associations in a clean way. Here's the controller code:
#listing = current_user.listings.build(params[:listing].permit(ATTRIBUTES_FOR_CREATE))
This builds an entity with several nested associations, like this:
class ListingDataField < ActiveRecord::Base
belongs_to :listing
validates_presence_of :listing
end
However, when I do #listing.save in controller, I get validation errors on those nested ListingDataField entities that 'listing can't be blank'. If I understand correctly, AutosaveAssociation first validates and saves nested associations, and eventually saves top-level entity. Thus, it fails validating ListingDataField, because Listing is not yet saved.
But I believe it's right having :listing validation in ListingDataField, so I wouldn't consider removing this. I can see 2 solutions:
in transaction - save Listing record, then build nested associations
one by one
#listing.save(:validate => false) but this is too ugly
Both aren't as much elegant as current_user.listings.build(...), so my question is - what is the proper Rails way for this?
P.S. I searched SO for similar question but I couldn't find any, hopefully this is not a duplicate :)
Have you tried adding:
class ListingDataField < ActiveRecord::Base
belongs_to :listing, inverse_of: :listing_data_fields
validates :listing, presence: true
end
and
class Listing < ActiveRecord::Base
has_many :listing_data_fields, inverse_of: :listing
end
This should make validation of presence work.
new to rails and trying to work out the most 'railsy' way to implement the following.
Given below:
class Team
has_many :team_memberships
has_many :players, through: :team_memberships
end
class TeamMembership
acts_as_list scope: :team_id
belongs_to :team
belongs_to :player
end
class Player
has_many :team_memberships
has_many :teams, through: team_memberships
end
In my TeamMembership model I have a additional columns position:integer, captain:boolean and wicket_keeper:boolean (Can you tell what I am working on yet.. :))
Given the following:
t = Team.first
p = Player.first(11)
t.players << p
This populates the TeamMembership model with my player objects nicely.
If I try:
t.players[4][:captain] = true
it fails with - ActiveModel::MissingAttributeError: can't write unknown attributecaptain'`
However, I can set it like this:
t.team_memberships[4][:captain] = true
But this just feels wrong.
Given you should see what I am trying to achieve, is this:
A) The best way to approach this task - if so, is there a way to get at and set the captain attribute directly through the player (if that makes sense)
or
B) Is there a better, more 'railsy' approach that I am missing.
I believe what you have t.team_memberships[4][:captain] = true is correct. I say this because you state in your question that your TeamMembership model has position:integer, captain:boolean, wicket_keeper:boolean. So from my understanding you've populated the TeamMembership model. However with the following: t.players[4][:captain] = true you are trying to access the captain attribute. Which is part of the TeamMembership model, and so what I'm trying to say is that your trying to access the attribute captain which an attribute of the instance TeamMembership. Further to this I believe this error is coming from the has_many :team_memberships which you have in your Player class, this refers to the associated model. I think its looking for player_id in the TeamMembership table. See the following links they may help clarify what you are trying to do:
API - Ruby on Rails - belongs_to
Guide Ruby on Rails - Belongs_to_association-reference have a look at section 4.1.2.6: foreign_key
I've got polymorphic association which looks like
class Certificate < ActiveRecord::Base
attr_accessible :certification_id, :certified_id, :certified_type
belongs_to :certification
belongs_to :certified, :polymorphic => true
end
class Certification < ActiveRecord::Base
attr_accessible :name, :slug
belongs_to :association
end
class Association < ActiveRecord::Base
has_many :certifications
attr_readonly :name, :id
attr_protected :name
end
assuming User model
class User < ActiveRecord::Base
has_many :certificates, :as => :certified
end
i am trying to access association object from within polymorphic association
u = User.first
u.certificates returns array of instances of Certificate
u.certificates.first.certification returns instance of Certification
but
u.certificates.first.certification.association returns stack level too deep error and on the second run console/server crashes with illegal hardware instruction message
I do realize that this expression is hardly a queen of code beauty, but it should work, shouldn't it?
Firstly I think that Association may be an unfortunate choice for a model name.
ActiveRecord::Base already has an instance method called association which you've just overridden for your Certification model by setting up an association to a model called Association. I haven't had a chance to trace exactly what that's going to do, but I'd guess a method called "association" is probably quite important in reflecting on and operating over a model's associations and overriding it is going to have exciting consequences.
I'd also suggest that given how awkward the above paragraph is to read that Association maybe isn't an optimal name for a Rails model anyway!
Try renaming that model and the associations to it to see if it fixes your problem.
I'm having a problem with some associations in Rails3.
I have the following associations
InformationCategory :has_many => Informations :has_many => InformationValues
I'm able to succesfully do the following:
Information.first.information_values
=> [#InformationValue..]
I'm also able to do the following:
InformationCategory.first.informations
=> [#Information...]
However, for some reason, this fails:
InformationCategory.first.informations.first.information_values
=> NoMethodError: undefined method `information_values' for #<Information:0x000001053321c8>
Why can't I use 'nested associations' in Rails? The error message clearly states that InformationCategory.first.informations.first returns an instance of Information
Am I doing something wrong?
Thanks in advance!
You don't define all the nested descendants on outermost model: each model defines what it "directly" has_many of, or the model it belongs_to. Because your question is wrong, I can only guess without seeing more specifically how your models are supposed to be related.
This might be a start:
class InformationCategory < ActiveRecord::Base
has_many :informations
end
class Information < ActiveRecord::Base
belongs_to :information_category
has_many :information_values
end
class InformationValue < ActiveRecord::Base
belongs_to :information
end
However, you might be trying to do a has_many :through, but I can't tell from your question.