Problem: I have a model Exercise
, this model can have exercises that are variations of each other. So a self join table I thought.
Like a join table of Foo, Boo, Coo
, where Foo
and Boo
are models link by the joining table Coo
allows for @foo.boo
and @boo.foo
So I looked and read these posts describing bi and uni directional relation ships 1, 2. So the table stores the data correctly but now I'm have trouble on creating the correct query.
Using the methods listed above, saving a record => Foo.variation_exercises = Boo
Which then allows @foo.exercises = boo
but if I do @boo.exercises
it returns an empty collection, instead of foo
. In order to get foo
it would be @boo.variations
.
What are the steps I need to take to make @foo.exercises
and @boo.exercises
work? Is it something to do with the foreign_key
or migration file?
Schema migration, Models, Controllers, Forms:
create_table :exercise_variation_relations do |t|
t.references :exercise, foreign_key: true, null: false, index: true
t.references :exercise_variation, foreign_key: { to_table: :exercises }, null: false, index: true
end
class ExerciseVariationRelation < ApplicationRecord
belongs_to :exercise, foreign_key: "exercise_id", class_name: "Exercise"
belongs_to :exercise_variation, foreign_key: "exercise_variation_id", class_name: "Exercise"
end
class Exercise < ApplicationRecord
**other code
has_many :exercise_drills, foreign_key: :exercise_variation_id, class_name: "ExerciseVariationRelation"
has_many :exercises, through: :exercise_drills, source: :exercise
has_many :variation_exercises, foreign_key: :exercise_id, class_name: "ExerciseVariationRelation"
has_many :variations, through: :variation_exercises, source: :exercise_variation
validates_associated: :variation_exercises
accepts_nested_attributes_for :variation_exercises
** other code
end
Contoller
params.fetch(:exercise, {}).permit( **other params
variation_exercises_attributes: [:id, :exercise_variation_id, :_destroy], )
Form
<%= f.fields_for :variation_exercises, ExerciseVariationRelation.new, child_index: 'NEW_RECORD' do |e| %>
<%= render "form_variation", form: e %>
<% end %>
Form_variation
<%= content_tag :div, class: "nested-fields" do %>
<%= form.collection_select(:exercise_variation_id, Exercise.all, :id, :name, {}, {class: 'form-control'}) %>
<% end %>
I understand how join tables work but this self join/relation is confusing still.
CodePudding user response:
ActiveModel::UnknownAttributeError (unknown attribute 'exercise_variation_id' for Exercise.)
The error message is clearly Exercise doesn't have exercise_variation_id.
Could you show your app/db/schema.rb
file content?
Make sure your migration creates exercise_variation_id for Exercise in the database.
CodePudding user response:
i think your model (at least how it is presented in your question) needs some clarification :) for instance:
- do these relations act like a transitive network? if A is a variation of B and B is a variation of C, does that make A a variation of C?
- if A is a variation of B, does that make B a variation of A?
in the simplest case, this should work i think:
create_table :exercise_variations do |t|
t.references :exercise, foreign_key: true, null: false, index: true
t.references :variation, foreign_key: { to_table: :exercises }, null: false, index: true
end
class ExerciseVariation < ApplicationRecord
belongs_to :exercise, foreign_key: "exercise_id"
belongs_to :variation, foreign_key: "variation_id", class_name: "Exercise"
end
class Exercise < ApplicationRecord
has_many :exercise_variations, class_name: "ExerciseVariation"
has_many :variations, through: :exercise_variations
has_many :variation_exercises, foreign_key: :variation_id, class_name: "ExerciseVariation"
has_many :variations, through: :variation_exercises
end