orgertot
orgertot

Reputation: 197

Rails: find_or_create relation

My field member_id is empty if I create a new exercise for a workout.

workout.rb

     belongs_to :member
     has_and_belongs_to_many :exercises

     def add_exercise_with_name(exercise_name)
        self.exercises << Exercise.find_or_create_by(name: exercise_name)
      end

exercise.erb

has_and_belongs_to_many :workouts
belongs_to :member

exercise_controller.erb

def create
    @workout = current_user.workouts.find(params[:workout_id])
    @exercise = @workout.add_exercise_with_name(exercises_params['name'])
    redirect_to workout_path(@workout)
end

How could i add the member for the exercise?

Upvotes: 2

Views: 1981

Answers (3)

Anatoly
Anatoly

Reputation: 15530

If you follow associations, then foreign keys populate automatically. In controllers you can also use ActiveRecord requests through associations:

class Member < ActiveRecord::Base
  has_many :workouts
  has_many :exercises, through: :workouts
end


class Workout < ActiveRecord::Base
  belongs_to :member
  has_and_belongs_to_many :exercises
end


class Exercise < ActiveRecord::Base
  belongs_to :member
  has_and_belongs_to_many :workouts
end


class ExercisesController < ActionController::Base
  before_action :get_workout

  def create
    @workout.exercises.where(name: exercises_params['name']).first_or_create
    redirect_to workout_path(@workout)
  end

  private

  def get_workout
    @workout = current_user.workouts.find(params[:workout_id])
  end
end 

Upvotes: 0

Mohamad
Mohamad

Reputation: 35339

Pass the id as an extra parameter to the method.

def add_exercise_with_name(exercise_name, member_id)
  self.exercises << Exercise.find_or_create_by(name: exercise_name, member_id: member_id)
end

This has a side effect. Now the find_or_create call will consider the member_id when looking up the Exercise. If this is not desirable, use create_with(member_id: member_id).

self.exercises << Exercise.create_with(member_id: member_id).find_or_create_by(name: exercise_name)

Furthermore, you can use block syntax:

  self.exercises << Exercise.find_or_create_by(name: exercise_name) do |exercise|
    exercise.member_id = member_id
  end

Upvotes: 3

Anthony Atkinson
Anthony Atkinson

Reputation: 3248

Try this on your Workout model:

def add_exercise_with_name(exercise_name, member)
  self.exercises << Exercise.find_or_create_by(name: exercise_name, member: member)
end

Then pass in the member in your controller:

member = Member.find_by whatever_column: 'value'
@exercise = @workout.add_exercise_with_name(exercises_params['name'], member)

Upvotes: 1

Related Questions