I'm building a Rails application with two models, both with a further two nested models:
Contacts -> Trackers -> Emails
and
Goals -> Stages -> Templates
I want to display information from a specific Goal on the show page of a particular Tracker but I'm struggling to get the right data to appear.
I have a field for goal_id in my Tracker parameters and I've added this line to my Tracker controller but I think I’m doing it wrong:
@goals = Goal.find(params[:id])
I'm sure it's going to be a really obvious mistake but I'm so new to Rails that I just can't seem to get it right and I'd love any suggestions you might have. Thanks in advance!
Model for Tracker:
class Tracker < ApplicationRecord
belongs_to :contact
has_one :goal
has_many :emails, dependent: :destroy
end
Model for Goal:
class Goal < ApplicationRecord
has_many :stages , dependent: :destroy
has_many :trackers
end
Controller for Tracker:
class TrackersController < ApplicationController
before_action :get_contact
before_action :set_tracker, only: %i[ show edit update destroy ]
# GET /trackers or /trackers.json
def index
@trackers = @contact.trackers
end
# GET /trackers/1 or /trackers/1.json
def show
@goals = Goal.find(params[:id])
end
# GET /trackers/new
def new
@tracker = @contact.trackers.build
end
# GET /trackers/1/edit
def edit
end
# POST /trackers or /trackers.json
def create
@tracker = @contact.trackers.build(tracker_params)
respond_to do |format|
if @tracker.save
format.html { redirect_to contact_trackers_path(@contact), notice: "Tracker was successfully created." }
format.json { render :show, status: :created, location: @tracker }
else
format.html { render :new, status: :unprocessable_entity }
format.json { render json: @tracker.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /trackers/1 or /trackers/1.json
def update
respond_to do |format|
if @tracker.update(tracker_params)
format.html { redirect_to contact_tracker_path(@contact), notice: "Tracker was successfully updated." }
format.json { render :show, status: :ok, location: @tracker }
else
format.html { render :edit, status: :unprocessable_entity }
format.json { render json: @tracker.errors, status: :unprocessable_entity }
end
end
end
# DELETE /trackers/1 or /trackers/1.json
def destroy
@tracker.destroy
respond_to do |format|
format.html { redirect_to contact_trackers_path(@contact), notice: "Tracker was successfully destroyed." }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def get_contact
@contact = Contact.find(params[:contact_id])
end
def set_tracker
@tracker = @contact.trackers.find(params[:id])
end
# Only allow a list of trusted parameters through.
def tracker_params
params.require(:tracker).permit(:name, :contact_id, :goal_id, :stage_id, :status, :note)
end
end
Show page view for Tracker:
<div class="card">
<h3>Goal</h3>
<%= @goals.name %>
</div>
in your TrackersController you have:
# GET /trackers/1 or /trackers/1.json
def show
@goals = Goal.find(params[:id])
end
It looks like you're taking a Tracker ID and using that ID as the ID of a Goal.
It's unlikely that (using 709 as an example) Tracker 709, is associated with Goal 709, so this is very likely an error. You do have an association between the models though, so you could use that to find the goal associated with the Tracker.
@goal = @tracker.goal
Note also in the above I'm using @goal
not @goals
since there's only one associated. You'll need to update your view to also use @goal
. Alternatively in your view you could just access the goal directly via @tracker.goal
; then you don't need to set @goal
at all.
Potential model issues: It looks like Tracker has_one goal
and Goal has_many trackers
. This looks like you wanted a normal n-to-1 relationship. So you probably want to change that has_one
to a belongs_to
instead. (It doesn't imply ownership.)
As is you're telling Rails:
Goal has_many trackers
-> the trackers
table has a goal_id
column that defines the relationship.Tracker has_one goal
-> the goals
table has a tracker_id
column that defines the relationship.I don't know what migration(s) you've run, but you probably only want one of these two columns (goal_id
and tracker_id
). You should take a look at your schema and fix this. (You may also want to try using the annotate_models gem so you can easily see the columns in your tables.)