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.
EDIT:
After reading more on how a join table
works and naming conventions I see that the methods are working like they should. My question should be about how do I not cause if statements
in the show
and form
page.
The way that it is set, if I was editing object a
that had a relation to object b
it would populate via the @a.variations
. However, if I go to object b
I have to get the relation via @b.exercises
which does not seem correct but works. Further more, the same idea would have to be repeated on the show
page. How does one go about making this a uniform "call" i.e. @a.variations and @b.variations to populate the forms
and the show
? Is it even possible?
UPDATE/Clarification: To question below regarding variations.
If there are many objects that are referenced, i.e. A
is a variation of B
and C
is a variation of B
then A
would also be a variation of C
. So a query of @a.variations = [B,C]
; @b.variations = [A,C]
; @c.variations = [A,B]
. Hopefully this clarifies the question and my thinking behind this relation/query.
(extra info)- The reason being some people wont be able to squat so they will have to start with a different exercise that target the same muscles and build there way up to the squat. Or you could have been injured or on a recovery day and to target the muscles with a less complex movement.
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