问题
I've been trying, for the last few months, to figure out how to set up an evaluation model so that some users can evaluate other users on their joint projects.
I previously asked this question, but have since had some advice that the suggestion to make this model polymorphic was not the right approach. I wasn't actually able to get the advice in this post working, but my question is now slightly different.
http://stackoverflow.com/questions/36394489/rails-4-polymorphic-associations-and-concerns
I have a user model and an evaluation model.
User
has_many :given_evaluations, foreign_key: :evaluator_id, dependent: :destroy, class_name: Evaluation
has_many :received_evaluations, foreign_key: :evaluatee_id, dependent: :destroy, class_name: Evaluation
Evaluation
belongs_to :evaluator, foreign_key: :evaluator_id, class_name: User
belongs_to :evaluatee, foreign_key: :evaluatee_id, class_name: User
I'm now trying to figure out how to setup the form so that the right user gets the evaluation and to limit the which user can leave the feedback.
In the evaluation form, I have:
<%= simple_form_for(@evaluation) do |f| %>
<%= f.error_notification %>
<div class="form-inputs">
<%= f.input :overall_score, collection: 1..10, autofocus: true, :label => "How do you rate this project experience (1 being did not meet expectations - 10 being met all expectations) ?" %>
<%= f.input :project_score, collection: 1..10, :label => "How successful was the project (1 being did not meet expectations - 10 being met all expectations)?" %>
<%= f.input :continue_project?, as: :boolean, checked_value: true, unchecked_value: false, :label => "Do you intend to continue working on the project?" %>
<%= f.input :remark, as: :text, :label => "Evaluate your project experience", :input_html => {:rows => 10} %>
</div>
<div class="form-actions">
<%= f.button :submit %>
</div>
<% end %>
In my evaluations controller, I have:
class EvaluationsController < ApplicationController
before_action :set_evaluation, only: [:show, :edit, :update, :destroy]
# before_filter :get_user, only: [:show, :edit, :update, :destroy]
# GET /evaluations
# GET /evaluations.json
def index
@evaluations = Evaluation.all
end
# GET /evaluations/1
# GET /evaluations/1.json
def show
@received_evaluations = @user.received_evaluations
end
# GET /evaluations/new
def new
@evaluation = Evaluation.new
end
# GET /evaluations/1/edit
def edit
end
# POST /evaluations
# POST /evaluations.json
def create
@evaluation = Evaluation.new(evaluation_params)
respond_to do |format|
if @evaluation.save
format.html { redirect_to @evaluation, notice: 'Evaluation was successfully created.' }
format.json { render :show, status: :created, location: @evaluation }
else
format.html { render :new }
format.json { render json: @evaluation.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /evaluations/1
# PATCH/PUT /evaluations/1.json
def update
respond_to do |format|
if @evaluation.update(evaluation_params)
format.html { redirect_to @evaluation, notice: 'Evaluation was successfully updated.' }
format.json { render :show, status: :ok, location: @evaluation }
else
format.html { render :edit }
format.json { render json: @evaluation.errors, status: :unprocessable_entity }
end
end
end
# DELETE /evaluations/1
# DELETE /evaluations/1.json
def destroy
@evaluation.destroy
respond_to do |format|
format.html { redirect_to evaluations_url, notice: 'Evaluation was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_evaluation
@evaluation = Evaluation.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def evaluation_params
params[:evaluation].permit(:overall_score, :project_score, :personal_score, :remark, :work_again?, :continue_project?)
end
end
Have I got the controller action for show correct? Do I need to put something in the controller to identify which user is receiving the evaluation and which is giving the evaluation. Do I need to add the :user_id to the permitted params in the evaluations controller?
How do I change the form to identify the correct user that's receiving the evaluation.
My routes are:
resources :evaluations
devise_for :users, #class_name: 'FormUser',
:controllers => {
:registrations => "users/registrations",
# :omniauth_callbacks => "users/authentications"
:omniauth_callbacks => 'users/omniauth_callbacks'
}
# get '/auth/:provider/callback' => 'users/authentications#create'
# get '/authentications/sign_out', :to => 'users/authentications#destroy'
# PER SOURCEY TUTORIAL ----------
match '/users/:id/finish_signup' => 'users#finish_signup', via: [:get, :patch], :as => :finish_signup
Workflow
- A user creates a project (owner)
- The owner invites classmates to join the project (team mates)
- If team mates accept by the cut off date, the users involved in the project complete the project.
- Once complete, each user evaluates the other users involvement in the project and the project itself. To do that, each user that is involved in the project sees a button on their user page, to get a link to the evaluation form. I need to figure out how to reference the other user ids for the team mates as well as the project they worked on.
The reason why I didn't nest the evaluation route inside the user routes is that I might try (if I can figure out this part first) to separate project evaluation from team mate evaluation, in which case, I'd like to use evaluation for two purposes. I'll come back to that later. For now, the evaluation model is on a user.
Finally, I use devise gem for user authentication.
PROBLEMS IDENTIFYING EVALUATEE
Taking Paul's suggestion for how to identify the evaluate_id, I added this select to my evaluation form:
<%= f.select :evaluatee_id, User.all.map{|u| [u.formal_name]} %>
Paul suggested including u.id inside the [] of this line. I don't understand how all the pieces fit together in this line of code (or what map means) but I will try again to find explanations of those issues separately. I removed the u.id, because I was getting the error below (it turns out that removing it still leads to the error below):
Couldn't find Evaluation with 'id'=7 [WHERE "evaluations"."evaluatee_id" = ?]
I can see from the console that the evaluation is saving, but it is not recording the evaluatee_id.
Evaluation.last
Evaluation Load (10.3ms) SELECT "evaluations".* FROM "evaluations" ORDER BY "evaluations"."id" DESC LIMIT 1
=> #<Evaluation id: 7, evaluatee_id: 0, overall_score: nil, project_score: nil, personal_score: nil, remark: "edededededede", work_again?: nil, continue_project?: nil, created_at: "2016-06-10 02:08:44", updated_at: "2016-06-10 02:08:44", evaluator_id: 34>
The error message points to the show action in my evaluations controller, which has:
def show
# @received_evaluations = @user.received_evaluations
@received_evaluation = current_user.received_evaluations.find params[:id]
end
回答1:
I agree that polymorphic associations are the wrong approach here.
You should do this in your #create
method to automatically record evaluations with the correct evaluator:
def create
# change this: @evaluation = Evaluation.new(evaluation_params)
# to this:
@evaluation = current_user.given_evaluations.build(evaluation_params)
# ... the rest is fine as-is ...
end
The current_user
comes from Devise and returns whatever user is currently logged in.
I would also make sure that #update
does current_user.given_evaluations.find(params[:id])
, so that you can't change evaluations you haven't written. Same for #destroy
.
Depending on your requirements you may want to access other methods in a similar way.
Your #show
method looks wrong to me. It should only find one evaluation:
def show
@received_evaluation = current_user.received_evaluations.find params[:id]
end
Also #index
should probably be scoped to the current user. Possibly you want to show evaluations you gave plus evaluations you received:
def index
@given_evaluations = curent_user.given_evaluations
@received_evaluations = curent_user.received_evaluations
end
EDIT: To set the evaluatee_id
, just pass it like any other param. First, permit it to come from the front end:
def evaluation_params
params[:evaluation].permit(
:overall_score, :project_score, :personal_score,
:remark, :work_again?, :continue_project?, :evaluatee_id)
end
Then add a widget to your form to let users provide it. For instance it could be a <select>
listing all the users:
<%= f.select :evaluatee_id, User.all.map{|u| [u.id, u.name]} %>
This will generate HTML something like this:
<select name="evaluation[evaluatee_id]">
<option value="1">Joe</option>
<option value="2">Sarah</option>
<option value="3">Fred</option>
</select>
In the above, 1
, 2
, and 3
are the IDs of the users you can choose to evaluate. The contents of each <option>
are their names. The browser will submit the option value (the ID) of whichever evaluatee you choose.
Of course you should change u.name
to whatever column/method you actually use to name users, e.g. email
or full_name
or whatever. Also you might want to sort and filter the list---whatever is appropriate for your app.
Also note that using a <select>
is just one option. You could have evaluators choose the evaluatee on a prior page, and pass it through the form as a hidden field instead. Or whatever you like! The point is that as long as the front end is sending an evaluation[evaluatee_id]
, you can save it like any other param.
来源:https://stackoverflow.com/questions/37610784/rails-feedback-on-specific-users-how-to-set-up-the-form-to-identify-relevant