J. Hübotter J. Hübotter - 3 months ago 32
Ruby Question

Rails 4 Error: ActiveRecord::AssociationTypeMismatch




Hey there,

I am fairly new to Rails and I've managed to create a Favorite controller for my Items(Tools) and Users.
I am displaying all Favorited Items(Tools) by a user correctly on his index. On the search view I provide links to favorite and unfavorite, but I am getting an error when I click on this link of a certain Item(Tool)

I am getting this error in the browser when favoriting an item:

ActiveRecord::AssociationTypeMismatch in ToolsController#favorite
Tool(#46153692) expected, got NilClass(#20297664)


The Request Parameters

{"_method"=>"put",
"authenticity_token"=>"vlWYHcp1K4Eu8WzjyEM8f6Eta9MNjgojtkr6RlG6n7121PGiWtXU8kDq9yXOfzGzw5grSc4GCqlcoK1UiLEsng==",
"type"=>"favorite", #WhatMyUserDid
"id"=>"1"} #MyUserId


My goal is to add a favorited Item(Tool) for a User (=> Error), show favorited Items(Tools) on Users index view (works fine), and show the link to Favorite or Unfavorite depending on the Favorites of the current_user (not implemented yet)

Here is my code:

app/models/favorite_tool.rb

class FavoriteTool < ActiveRecord::Base
belongs_to :tool
belongs_to :user
end


app/models/tool.rb

class Tool < ActiveRecord::Base
belongs_to :user

# Favorited by users
has_many :favorite_tools # just the 'relationships'
has_many :favorited_by, through: :favorite_tools, source: :user # the actual users favoriting a tool


mount_uploader :cover_filename, CoverUploader
end


app/models/user.rb

class User < ActiveRecord::Base

# Include default devise modules. Others available are:

# :confirmable, :lockable, :timeoutable and :omniauthable

devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable


has_many :tools

# Favorite tools of user
has_many :favorite_tools # just the 'relationships'
has_many :favorites, through: :favorite_tools, source: :tool # the actual tools the user favorites


mount_uploader :avatar_filename, AvatarUploader

end


app/controllers/tools_controller.rb

class ToolsController < ApplicationController
before_action :find_tool, only: [:show, :edit, :update, :destroy]

# Add and remove favorite recipes
# for current_user
def favorite
type = params[:type]
if type == "favorite"
current_user.favorites << @tool
redirect_to :back, notice: 'You favorited #{@tool.title}'

elsif type == "unfavorite"
current_user.favorites.delete(@tool)
redirect_to :back, notice: 'Unfavorited #{@tool.title}'

else
# Type missing, nothing happens
redirect_to :back, notice: 'Nothing happened.'
end
end

def index
@favorites = current_user.favorites
@tools = Tool.where(user_id: current_user).order("created_at DESC")
@user = current_user
end

def search
@tool = Tool.find(1)
@tools = Tool.all.order("created_at DESC")
end

def show
end

def new
@tool = current_user.tools.build
end

def create
@tool = current_user.tools.build(tool_params)

if @tool.save
redirect_to tools_path
else
render 'new'
end
end

def edit
end

def update
if @tool.update(tool_params)
redirect_to tools_path
else
render 'edit'
end
end

def destroy
@tool.destroy
redirect_to tools_path
end

private

def find_tool
@tool = Tool.find(params[:id])
end

def tool_params
params.require(:tool).permit(:title, :subtitle, :url, :cover_filename)
end
end


app/views/tools/index.html.haml

%h2 My Favorite Tools
- @favorites.each do |tool|
= image_tag tool.cover_filename.url
%h2= link_to tool.title, tool
%p= tool.subtitle
%p= link_to "Edit", edit_tool_path(tool)
%p= time_ago_in_words(tool.created_at)


app/views/tools/search.html.haml

- @tools.each do |tool|
= image_tag tool.cover_filename.url
%h2= link_to tool.title, tool
%p= tool.subtitle
%p= link_to tool.user.try(:username), '/users/'+tool.user_id.to_s
%p= link_to "Favorite", favorite_tool_path(@tool, type: "favorite"), method: :put
%p= link_to "Unfavorite", favorite_tool_path(@tool, type: "unfavorite"), method: :put
%p= link_to "Edit", edit_tool_path(tool)
%p= time_ago_in_words(tool.created_at)


app/config/routes.rb

resources :tools do
put :favorite, on: :member
end


I hope the provided data is enough, if not please tell me. I'm grateful for all Your replies.

Answer

Your before_action needs to include :favorite as you are not defining the @tool in your favorite action.