AssociationTypeMismatch nested attributes

I'm running into an issue with an associated model. I have a nested attributes for my user, to a reviewer. A user can essentially review another person, thus be a reviewer and be the person reviewed.

It's set up like this:

  # User
  has_many :reviewers
  accepts_nested_attributes_for :reviewers
  has_many :active_managements, class_name: 'Reviewer',
                                foreign_key: 'reviewer_id',
                                dependent: :destroy


class Reviewer < ActiveRecord::Base
  belongs_to :user
  belongs_to :reviewer_id, class_name: 'User'
end

now in my users controller I have:

class UsersController < ApplicationController


  def edit
    @user = User.find(params[:id])
    @user.reviewers.build
    redirect_to root_url && return unless @user.activated?
  end

  def update
    @user = User.find(params[:id])
    if @user.update_attributes(user_params)
      redirect_to edit_user_path(@user)
    else
      render 'edit'
    end
  end

  private

  def user_params
    params.require(:user).permit(:invitation_token, :first_name, :admin,
                                 :last_name, :title, :email, :password,
                                 reviewers_attributes: [:reviewer_id])
  end

the error that I get is:

User(#70197180889680) expected, got String(#70197172430700)

happening on "user_params", so I assume it has to do with my attributes. Anybody know what's up?

Upvotes: 1

Views: 1283

Answers (2)

Richard Peck
Richard Peck

Reputation: 76784

The immediate fix is here:

#app/models/review.rb
class Reviewer < ActiveRecord::Base
   belongs_to :reviewer
end

--

This is how I'd fix the systemic issue:

#config/routes.rb
resources :users do
   resources :reviewers #-> url.com/users/:user_id/reviews/new
end

#app/controllers/reviewers_controller.rb
class ReviewersController < ApplicationController
   def new
       @user = User.find params[:user_id]
       @review = user.reviewers.new
   end

   def create
       @user = User.find params[:user_id]
       @review = user.reviewers.new reviewer_params
   end

   private

   def review_params
      params.require(:reviewer).permit(:user_id, :reviewer_id)
   end
end

Models

Apart from this, I think your main issue is the way your models are set up.

Ideally, you want to have reviewer and user as the same data-set (I presume they're both users), which makes your current setup really inefficient...

#app/models/user.rb
class User < ActiveRecord::Base
   has_and_belongs_to_many :reviewers,
      class_name:              "User",
      join_table:              :reviewers_users
      foreign_key:             :user_id,
      association_foreign_key: :reviewer_id
end

What you're looking for is something called a self referrential association, which basically allows you to associate the same model in a many-to-many relationship.

In most cases, this will be used with a has_and_belongs_to_many relationship; you could also use a has_many :through although it's not as common.

The above will allow you to use the following:

@user = User.find params[:id]
@user.reviewers #-> collection of users who are reviewers of original user

Upvotes: 1

basiam
basiam

Reputation: 1567

The line belongs_to :reviewer_id, class_name: 'User' is incorrect. Try changing it to something like belongs_to :reviewing_user, class_name: 'User' (replacing reviewing_user with whatever name you want to use for this association :), not field name.

http://apidock.com/rails/ActiveRecord/Associations/ClassMethods/belongs_to

Upvotes: 3

Related Questions