Rails 4 many-to-many associations nightmare - ruby-on-rails

I'm trying to set up a has_many :through association between three models: Trip, Location and LocationsTrip, but the associations just don't seem to be picking each other up.
I set up my associations:
class Trip < ActiveRecord::Base
belongs_to :user
has_many :locations_trips
has_many :locations, :through => :locations_trips
accepts_nested_attributes_for :locations_trips, :allow_destroy => :true
accepts_nested_attributes_for :locations, :allow_destroy => :true
end
class Location < ActiveRecord::Base
has_many :locations_trips, :dependent => :destroy
has_many :trips, :through => :locations_trips
end
class LocationsTrip < ActiveRecord::Base
belongs_to :locations
belongs_to :trips
end
When I run Trip.last.locations in the Rails console I get
NameError: uninitialized constant Trip::Locations
so I've obviously missed something crucial, but I feel as if I've been through every similar answer on here and can't see where I'm going wrong.
It's probably worth mentioning I'm trying to set this up with Trips accepting nested attributes for Locations so in the Trip form partial I've got a f.fields_for :locations do |builder| etc, but when I load up the page I get the same NameError as before.
If anyone can point me in the right direction I'd be massively grateful - I feel like I'm getting tunnel vision on this.
I'm using Ruby 2.1.2 and Rails 4.2.0.

It looks like you're using plural names for the join table belongs_to associations. Try changing to:
class LocationsTrip < ActiveRecord::Base
belongs_to :location
belongs_to :trip
end

Related

rails 2.2 - polymorphic has_many without using has_polymorphs

I'm trying to set up some new classes and associations in a Rails 2.2.2 app (please don't ask me to upgrade it).
The idea is that there is a Conversation class. It can have many participants, which are a mix of User and Pupil records, and it can have many owners, which can be a mix of a variety of things, including User and Pupil records. This is what I have so far:
#the :owner association can point to *anything*, including a Pupil or User record
class ConversationOwnership < ActiveRecord::Base
belongs_to :conversation
belongs_to :owner, :polymorphic => true
end
#the :participant association will point to either a Pupil or User record
class ConversationParticipant < ActiveRecord::Base
belongs_to :conversation
belongs_to :participant, :polymorphic => true
end
class Conversation < ActiveRecord::Base
has_many :conversation_ownerships
has_many :owners, :through => :conversation_ownerships
has_many :conversation_participants
has_many :participants, :through => :conversation_participants
end
This currently isn't working:
Conversation.first.participants
=> ActiveRecord::HasManyThroughAssociationPolymorphicError: Cannot have a has_many :through association 'Conversation#participants' on the polymorphic object 'Participant#participant'.
Now, I know that the has_many_polymorphs plugin was designed to solve this very problem, but the problem with using that is that it automatically makes associations for each of the listed classes, and because User and Pupil are in both participants and owners, they would clash:
OWNER_CLASSES = [:ilps, :lessons, :digilearning_modules, :resources, :pupil_groups, :pupils, :users]
PARTICIPANT_CLASSES = [:pupils, :users, :contacts, :parent_carers]
has_many_polymorphs :participants, :from => PARTICIPANT_CLASSES, :through => :conversation_participants, :order => "conversation_participants.created_at"
has_many_polymorphs :owners, :from => OWNER_CLASSES, :through => :conversation_ownerships, :order => "conversation_ownerships.owner_type, conversation_ownerships.created_at"
With this, the first hmp makes a .pupils association which effectively means "participants that are Pupils", and the second hmp also makes a .pupils association which effectively means "owners that are Pupils".
I don't want these extra associations that has_many_polymorphs brings, which is why i thought I would roll my own associations. But, I can't get past that Cannot have a has_many :through association 'Conversation#participants' on the polymorphic object 'Participant#participant'. error.
This feels like it should be possible - is it?

accepts_nested_attributes_for causing infinite loop in rails_admin

I have two models that both accept_nested_attributes_for each other. I know this is causing issues with rails_admin but can't seem to figure out the appropriate command to exclude nested attributes in my configuration. Ideally I would like to exclude nested attributes for all models so that this problem does not happen again.
Branden,
You need to inform the bi-direction association using inverse_of:
Ex:
class User < ActiveRecord::Base
belongs_to :company, :inverse_of => :users
accepts_nested_attributes_for :company
end
For both sides of association:
class Company < ActiveRecord::Base
has_many :users, inverse_of: :company
accepts_nested_attributes_for :users, :allow_destroy => true
end
More information in the docs: http://guides.rubyonrails.org/association_basics.html#bi-directional-associations

Source Reflection Errors with has_many :through

I'm attempting to create a system where my site's users can favorites pages. Those pages have two types, either clubs or sports. So, I have four models, associated as such:
User Model:
class User < ActiveRecord::Base
..
has_many :favorites
has_many :sports, :through => :favorites
has_many :clubs, :through => :favorites
..
end
Favorites Model:
class Favorite < ActiveRecord::Base
..
belongs_to :user
belongs_to :favoritable, :polymorphic => true
end
Club Model:
class Club < ActiveRecord::Base
..
has_many :favorites, :as => :favoritable
has_many :users, :through => :favorites
def to_param
slug
end
end
Sport Model:
class Sport < ActiveRecord::Base
..
def to_param
slug
end
..
has_many :favorites, :as => :favoritable
has_many :users, :through => :favorites
..
end
Essentially, the User has_many sports or clubs through favorites, and the association between favorites, sports, and clubs is polymorphic.
In practice, this is all working exactly the way I want it to, and the whole system I have designed works. However, I'm using Rails_Admin on my site, and I get an error in three places:
When loading the Dashboard (/admin) the first time. If I refresh the page, it works fine.
When loading the User model in Rails_Admin
When loading the Favorites model in Rails_Admin
Here is the error message on /admin/user (gist). All of the errors are similar, referencing ActiveRecord::Reflection::ThroughReflection#foreign_key delegated to source_reflection.foreign_key, but source_reflection is nil:.
Can anyone point me in the right direction so that I can fix this? I've searched all over, and asked other programmers/professionals, but no one could spot the error in my models. Thanks so much!
Alright, well, I finally worked this out, and figured that I'd post the fix just in case it helps someone else out in the future (no one likes finding someone else with the same problem and no posted answer).
As it turns out, with a polymorphic has_many :through, there is a little more configuration needed. My User model should have looked like this:
class User < ActiveRecord::Base
..
has_many :favorites
has_many :sports, :through => :favorites, :source => :favoritable, :source_type => "Sport"
has_many :clubs, :through => :favorites, :source => :favoritable, :source_type => "Club"
..
end
This answer to another question about polymorphic has_many :through associations is what helped me figure this out.
I encountered this error when the code included a has_many for an association that doesn't exist (mid-refactor). So it can also be caused by some general has_many misconfigure. The Ruby/Rails code never cares because the dynamic style of Ruby means the association is only called on demand. But Rails-Admin exhaustively inspects properties, leading to reflection problems.

Trouble with has_many :through => association

Caution: I am a 4 week old at programming. I am having trouble with a has_many :through => relationship between my Neighborhood and Cta_train models.
Here are my models:
class CtaTrain < ActiveRecord::Base
belongs_to :Ctaline
has_and_belongs_to_many :searches
has_many :neighborhoods, :through => :CtaLocation, :foreign_key => :neighborhood_id
has_many :CtaLocations
end
class Neighborhood < ActiveRecord::Base
has_many :geopoints
has_many :listings
has_many :properties
has_and_belongs_to_many :searches
has_many :CtaTrains, :through => :CtaLocation, :foreign_key => :cta_train_id
has_many :CtaLocations
end
class CtaLocation < ActiveRecord::Base
belongs_to :neighborhood
belongs_to :CtaTrain
end
When I try to do this:
neighborhood.CtaTrains
I get this error:
ActiveRecord::HasManyThroughAssociationNotFoundError (Could not find the association :CtaLocation in model Neighborhood):
I have been slogging through this for several hours now....I have tried many iterations of ideas from stackoverflow....what I show above feels like the closest solution, but obviously still not working. Any thoughts would be appreciated!
I think the problem is that you're not following Rails conventions by using lowercase/underscore for your symbols. Class names have to be CamelCase but you should be doing the following everywhere else:
class CtaTrain < ActiveRecord::Base
belongs_to :cta_line
has_and_belongs_to_many :searches
has_many :neighborhoods, :through => :cta_locations, :foreign_key => :neighborhood_id
has_many :cta_locations
end
*Update: You should also be using :cta_locations (plural) in your has many through

Undefined method when accessing through association and uninitialized constant when trying to destroy with :dependent => :destroy

I've tried persistently googling this error, but to no avail. I currently have these models
app/models/survey.rb
class Survey < ActiveRecord::Base
belongs_to :user
has_attached_file :original, :default_url => "/public/:class/:attachment/:basename.:extension"
has_many :sub_surveys, :dependent => :destroy
end
app/models/sub_survey.rb
class SubSurvey < ActiveRecord::Base
belongs_to :survey
has_many :questions, :dependent => :destroy
end
app/models/question.rb
class Question < ActiveRecord::Base
belongs_to :sub_survey
validates_presence_of :sub_survey
acts_as_list :scope => :sub_survey
#after_destroy :destroy_orphaned_choices
has_many :answers, :dependent => :destroy
has_many :choices, :dependent => :destroy
end
app/models/choice.rb
class Choices < ActiveRecord::Base
belongs_to :question
validates_presence_of :question
end
app/models/answer.rb
class Answer < ActiveRecord::Base
belongs_to :question
belongs_to :user
belongs_to :game
validates_uniqueness_of :question_id, :scope => [:user_id, :game_id]
end
Now when I try to destroy a survey, I get an error
uninitialized constant Question::Choice
That traces through /vendor/rails/active* stuff after the survey.destroy
Then when I try to access choices from question.Choices, I get an error
undefined method `Choices' for #<Question:0xb7224f2c>
which for some reason has this on top of the trace-stack
vendor/rails/activerecord/lib/active_record/attribute_methods.rb:256:in `method_missing'
vendor/plugins/attribute_fu/lib/attribute_fu/associations.rb:28:in `method_missing'
app/views/answers/_answer.html.erb:7:in `_run_erb_47app47views47answers47_answer46html46erb'
I do use attribute_fu when importing surveys in xml-format, but I have no idea why the trace of question.Choices has it.
I also tried renaming choices to choicealternatives, but that didn't have an effect.
Any ideas?
Your Choices table has already got a pluralised name which may be causing problems. Ideally that table should be called Choice otherwise your has_many :choices should specify the class_name option too. E.g.
has_many :choices, :class_name => 'Choices'
Though I'd opt for renaming the class and table Choice if you can.
Attachment_fu is probably appearing in the stack trace because they have overridden or aliased the method_missing method to add their own behaviour. It's not necessarily anything to be concerned about.
I'm not sure why you get the error when destroying a Survey, but you're getting this
undefined method `Choices' for #<Question:0xb7224f2c>
because you should be accessing it like this:
question.choices # No capitalization
I think that should solve one of the problems.

Resources