Evaluation - polymorphic associations on feedback

2019-07-23 04:59发布

问题:

I'm trying to figure out how to implement an evaluation model in my Rails 4 app.

I've previously asked these related questions but am yet to solve this problem:

Rails 4 Polymorphic associations and concerns

Rails 4 - post completion evaluations model - structure

I have:

class Evaluation < ActiveRecord::Base

  belongs_to :evaluator, :polymorphic => true
  belongs_to :evaluatable, :polymorphic => true

I have also made concerns for evaluator and evaluatable as:

module Evaluator
    extend ActiveSupport::Concern

    included do 
        has_many :given_evaluations, as: :evaluator, dependent: :destroy, class_name: 'Evaluation'

    end
end
module Evaluatable
    extend ActiveSupport::Concern

    included do 
        has_many :received_evaluations, as: :evaluatable, dependent: :destroy, class_name: 'Evaluation'
    end
end

I have included each concern in my user model:

class User < ActiveRecord::Base
   include Evaluator
   include Evaluatable

In my show page, I want to show a particular user's evaluations (received from other users -who are evaluators).

In my show, I have:

<% Evaluation.find(params[:id]).received_evaluations.order('created_at DESC').each do |eval| %>
                                <div id="portfolioFiltering" class="masonry-wrapper row">
                                        <%= eval.remark %>
                                        <%= eval.personal_score %>
                                        <small><%= eval.created_at %></small>

In my evaluations form, I"m not sure how to designate the recipient of the evaluation. I have made the basic form, but I'm not clear about how to tie it to the user who should receive the evaluation.

<%= simple_form_for(@evaluation) do |f| %>
  <%= f.error_notification %>

  <div class="form-inputs">
    <%= f.input :score, collection: 1..10, autofocus: true, :label => "How do you rate this experience (1 being did not meet expectations - 10 being met all expectations) ?" %>

    <%= f.input :remark, as: :text, :label => "Evaluate your project experience", :input_html => {:rows => 10}  %>

My evaluations table has:

    t.integer  "user_id"
    t.integer  "evaluatable_id"
    t.string   "evaluatable_type"
    t.integer  "overall_score"
    t.integer  "project_score"
    t.integer  "personal_score"
    t.text     "remark"
    t.boolean  "work_again?"
    t.boolean  "continue_project?"
    t.datetime "created_at",        null: false
    t.datetime "updated_at",        null: false
  end

  add_index "evaluations", ["evaluatable_type", "evaluatable_id"], name: "index_evaluations_on_evaluatable_type_and_evaluatable_id", unique: true, using: :btree

In my users controller, I have:

def show
    # authorize! :read, @user
    @received_evaluations = @user.received_evaluations
  end

I currently get an error that says:

undefined method `received_evaluations' for #<Evaluation:0x007fb8c4b32160>

I'm not sure what this message means or how to solve it.

If I change the show to:

<% @user.received_evaluations.each do |eval| %>

I get this error:

undefined method `received_evaluations' for nil:NilClass

回答1:

Reading your different questions on this issue I think what are are trying to set up a mechanism for one User to evaluate another User.

Based on the above logic, the use of polymorphic associations is not required. They are probably overcomplicating things for you.

This is what I think you need:

class User
  has_many :given_evaluations, foreign_key: :evaluator_id, class_name: Evaluation
  has_many :received_evaluations, foreign_key: :evaluatee_id, class_name: Evaluation
end

class Evaluation
  belongs_to :evaluator, foreign_key: :evaluator_id, class_name: User
  belongs_to :evaluatee, foreign_key: :evaluatee_id, class_name: User
end

Your evaluation table would be like this:

id                :integer          not null, primary key
evaluator_id      :integer          not null
evaluatee_id      :integer          not null
overall_score     :integer
continue_project  :boolean
created_at        :datetime         not null
updated_at        :datetime         not null

You can then do away with the Evaluator and Evaluatable modules.

So, now to display a user's received evaluations and get rid of the error messages you are receiving:

In the controller:

# ensure we get the user for all relevant routes
before_filter :get_user, only: [:show, edit, :update, :destroy]

def get_user
  @user = User.find(params[:id])
end

def show
  # get the received evaluations and order
  @received_evaluations = @user.received_evaluations
  @received_evaluations = @received_evaluations.order('created_at DESC')

  # you will probably want grab the evaluator record as well...
  @received_evaluations = @received_evaluations.includes(:evaluator)
end

And in the show view

<% @received_evaluations.each do |eval| %>
  <div id="portfolioFiltering" class="masonry-wrapper row">
    <%= eval.remark %>
    <%= eval.personal_score %>
    <small><%= eval.created_at %></small>
    ...
  </div>
<% end %>