Search code examples
ruby-on-railsfriendly-id

undefined method `username' for nil:NilClass when adding has_many through association


(Edit: See solutions included) I have a model, Goal, which uses friendly_id. I have it set up to add the username to the slug, and all was working great until I added a has_many_through association so users could participate in the Goals. I'm getting a undefined method 'username' for nil:NilClass error whenever I try to add a new goal now:

def slug_candidates
    [
      [user.username, :title]
    ]
  end

This is my model, goal.rb:

class Goal < ApplicationRecord

  belongs_to :user
  has_many :participations
  has_many :users, through: :participations

  # Solution 
  has_many :participations, dependent: :destroy
  has_many :participants, :through => :participations, :source => :user

  extend FriendlyId
  friendly_id :slug_candidates, use: :slugged
  delegate :username, to: :user, prefix: true

  def slug_candidates
    [
      [user.username, :title]
    ]
  end

  def should_generate_new_friendly_id?
    slug.blank? || title_changed?
  end
...

user.rb

class User < ApplicationRecord      
  extend FriendlyId
  friendly_id :username, use: :slugged

  validates :username, presence: true, length: { minimum: 4, maximum: 16 } 
  validates_uniqueness_of :username

  has_many :goals, dependent: :destroy
  has_many :participations, dependent: :destroy
  has_many :goals, through: :participations, source: :goal

  # Solution
  has_many :participations, dependent: :destroy
  has_many :participant_goals, through: :participations, :source => :goal

I have also tried using

  has_many :participations, dependent: :destroy
  has_many :goals, through: :participations, class_name: 'Goal'

The controller (Goal#create) that it says is giving me trouble.

def create
    @goal = current_user.goals.build(goal_params)

    respond_to do |format|
      if @goal.save
        format.html { redirect_to @goal, notice: 'New goal saved successfully!' }
      else
        format.html { render :new }
      end
    end
  end

Here is the participation model:

class Participation < ApplicationRecord
  belongs_to :user
  belongs_to :goal
  validates :user_id, presence: true
  validates :goal_id, presence: true
end

I get the feeling it has to do with the new association, but I can't figure out how to fix it. If I remove the

has_many :participations, dependent: :destroy
has_many :goals, through: :participations, source: :goal

from the user.rb model, it moves on to other error messages, so that is where I believe the trouble is.


Solution

  • This is your problem in the User model...

    has_many :goals, dependent: :destroy
    has_many :participations, dependent: :destroy
    has_many :goals, through: :participations, source: :goal
    

    You've defined has_many :goals twoice, so the line

    @goal = current_user.goals.build(goal_params)
    

    Doesn't build the @goal object correctly.

    Try this instead...

    has_many :goals, dependent: :destroy
    has_many :participations, dependent: :destroy
    has_many :participants_goals, through: :participations, class_name: 'Goal'