Search code examples
ruby-on-railsruby-on-rails-4activerecordassociationsbelongs-to

Rails Associations - Values are correct, but association is nil


I have been working on this all afternoon and I am so close, but my brain is just skipping over something simple, but I can't see it.

On this site, a user can create and join clubs. When a user joins a club, they join as a club member. Club members can make posts to the club. For some reason, I cannot get my club member to post association working properly. The value is getting filled in with the correct id, but when I check the association in the console, I am getting nil. My goal is to be able to get the username the club member that made a post.

User Model

has_many :club_memberships, :class_name => 'ClubMembership', :foreign_key => :member_id, :primary_key => :id 
has_many :clubs, :through => :club_memberships 

Club Model

has_many :club_memberships
has_many :members, :through => :club_memberships
has_many :posts

Club Membership Model

belongs_to :club 
belongs_to :member, :class_name => "User", :foreign_key => :member_id, :primary_key => :id 
has_many :posts

Post Model

belongs_to :club
belongs_to :club_membership

Relevant Routes

resources :clubs do
    resources :posts
end
  resources :club_memberships, :only => [:index, :create, :destroy] 

Posts Controller

class PostsController < ApplicationController
  before_action :set_post, only: [:show, :edit, :update, :destroy]
  before_action :set_club
  before_action :set_membership_id

  def new
    @post = Post.new
  end

  def show
    @posts = Post.find(params[:id])
  end

  def create
    @post = Post.new(post_params)
    @post.member_id = @club_membership.id
    @post.club_id = @club.id

    if @post.save
      redirect_to @club
    else
      render 'new'
    end
  end


  private
    def set_post
      @post = Post.find(params[:id])
    end

    def set_club
      @club = Club.find(params[:club_id])
    end

    def set_membership_id
      @club_membership = @club.club_memberships.find_by(member_id: current_user)
    end

    def post_params
      params.require(:post).permit(:title, :postcontent)
    end
end

The post is created by following the new_club_post_path(@club) link_to from the club page. The post is created properly and the values are correct.

Console result of a recent post

> @post = Post.find(7)
  Post Load (0.2ms)  SELECT  `posts`.* FROM `posts` WHERE `posts`.`id` = 7 LIMIT 1
 => #<Post id: 7, member_id: 29, club_id: 22, title: "fdsafsadfas", postcontent: "fsdafsadfsadfsadfasdf", created_at: "2015-10-16 22:39:28", updated_at: "2015-10-16 22:39:28"> 

Calling @post.club returns true

> @post.club
  Club Load (0.2ms)  SELECT  `clubs`.* FROM `clubs` WHERE `clubs`.`id` = 22 LIMIT 1
 => #<Club id: 22, club_name: "new test club", club_type: "Movies", created_at: "2015-10-16 22:34:51", updated_at: "2015-10-16 22:34:51"> 

but when I try @post.club_membership, the result is nil and I cannot figure out why that is.

> @post.club_membership
 => nil 

If I try to set a specific value to @club, I can call @club.club_memberships so I think that association is working fine. I am just having a problem going from post to club_membership. I am hoping to call something like this @post.club_membership.username and have the value return the associated username of the post. If I call that currently, I get

NoMethodError: undefined method `username' for nil:NilClass

Thanks!

edit-- Here is the create migration for the post table.

class CreatePosts < ActiveRecord::Migration
  def change
    create_table :posts do |t|
      t.integer :member_id
      t.integer :club_id
      t.string :title
      t.text :postcontent

      t.timestamps null: false
    end
  end
end

UPDATED Answer Thanks to the awesome users on this site, I was able to figure this out.

My Post Model should have this as the association:

belongs_to :club_membership, :class_name => 'ClubMembership', :foreign_key => :member_id, :primary_key => :id 

Which lets me call @post.club_membership.member.username to get the username of the poster to display.


Solution

  • As you've shown in your (excellent) question, your Post has the following attributes (as well as the timestamps and id):

    member_id: 29
    club_id: 22
    title: "fdsafsadfas"
    postcontent: "fsdafsadfsadfsadfasdf"
    

    Your Post model has the following associations:

    belongs_to :club
    belongs_to :club_membership
    

    The first of those will look for an attribute called club_id (and find it), the second will look for an attribute called club_membership_id and not find it. So the association method will never work.

    Judging by your code and question, I suspect that's all you needed someone to point out, but please let me know if your issue isn't clear to you though.