Sean Magyar
Sean Magyar

Reputation: 2380

rails attribute changes in spite of not being in form

I have rails app where users can assign tasks to each other. Every task has one assigner and one executor. By default the task creator(current_user) is always the assigner. Both of the assigner and executor are allowed to edit the same task.

My problem is the following. Let's say user.id=2 the assigner and user.id=1 is the executor. If the assigner (id=2) edits the task later on everything works fine, but if the executor (id=1) edits it then he becomes the assigner as well, so task.executor_id = 1 and task.assigner_id = 1. There is no option to change the assigner in the new/edit form. When assigner creates it he is the default assigner as current user and when sby tries to edit it he/she can't change the assigner. What causes this issue?

It's weird since it worked well earlier and I'm kinda sure that I have been experiencing this problem since I've changed to using the _task.html.erb partial with <%= render @tasks %> instead of going w/ the plain old @tasks.each do |task| version. I first thought it happened because I made some mistakes w/ the new AJAXified version, but after git reset --hard it seems to be something else.

def task_params
  params.require(:task).permit(:executor_id, :name, :content, :deadline, :task_name_company)
  .merge(assigner_id: current_user.id)
end

class Task < ActiveRecord::Base
  belongs_to :assigner, class_name: "User"
  belongs_to :executor, class_name: "User"

_task.html.erb

<% if current_user.id == task.assigner.id %>
  <tr style="background: #eaeaea" id="task_<%= task.id %>">
    <td class="col-md-3">
      <%= link_to user_path(id: task.executor.id) do %>
        <%= task.executor.profile.first_name %> <%= task.executor.profile.last_name%> / <%= task.executor.profile.company %>
      <% end %>
    </td>
<% else %>
  <tr id="task_<%= task.id %>">
    <td class = "col-md-3">
      <%= link_to user_path(id: task.assigner.id) do %>
        <%= task.assigner.profile.first_name %> <%= task.assigner.profile.last_name%> / <%= task.assigner.profile.company %>
      <% end %>
    </td>
<% end %>
    <td class="cold-md-4">
      <%= link_to user_task_path(id: task.id) do %>
        <%= task.content %>
      <% end %>
    </td>
    <td class="col-md-3">
      <%= task.deadline %>
    </td>
    <td class="col-md-2" style="padding:0px">
    <% if current_user.id == task.assigner.id %>
      <table class="table table-bordered inside-table" style="background:#eaeaea">
    <% else %>
      <table class="table table-bordered inside-table">
    <% end %>
        <tr>
          <td class="col-md-4" style="border-top:0px;border-bottom:0px;border-left:0px">
            <% if task.completed_at == nil %>
              <%= link_to complete_user_task_path(id: task.id), action: :complete, remote: true, method: :patch do %>
                <i class="fa fa-check"></i>
              <% end %>
            <% else %>
              <%= link_to uncomplete_user_task_path(id: task.id), action: :uncomplete, remote: true, method: :patch do %>
                <i class="fa fa-check"></i>
              <% end %>
            <% end %>
          </td>
          <td class="col-md-4" style="border-top:0px;border-bottom:0px;">
            <%= link_to edit_user_task_path(id: task.id), type: "button" do %>
              <i class="fa fa-pencil"></i>
            <% end %>
          </td>
          <td class="col-md-4" style="border-top:0px;border-bottom:0px;border-right:0px">
            <%= link_to user_task_path(id: task.id), method: :delete, data: { confirm: "Are you sure?" }, remote: true do %>
              <i class="fa fa-trash"></i>
            <% end %>
          </td>
        </tr>
      </table>
    </td>
  </tr>

_form.html.erb

<%= form_for ([@user, @task]) do |f| %>

  <%= render 'layouts/error_messages', object: f.object %>

  <div class="field form-group">
    <%= f.label :Name_or_Company %>
    <%= f.text_field :task_name_company, data: {autocomplete_source: user_tasknamecompanies_path}, class: "form-control task_name_company" %>
  </div>
  <div class="field form-group">
    <%= f.label :content %>
    <%= f.text_area :content, class: "form-control" %>
  </div>
  <div class="field form-group">
    <%= f.label :deadline %>
    <%= f.date_select :deadline, class: "form-control" %>
  </div>
  <div class="actions">
    <%= f.submit "Create Task", class: 'btn btn-primary', "data-sid" => current_user.id, "data-rip" => :executor_id %>
  </div>
<% end %>

UPDATE: Problem solved based on Rich Peck's and miler350's answers. I did the following:

before_action :set_assigner, only: :create

private

def set_assigner
  @task.assigner.id = current_user.id
end

Upvotes: 1

Views: 481

Answers (2)

Richard Peck
Richard Peck

Reputation: 76784

By default the task creator(current_user) is always the assigner

This should not matter - someone is the assigner and someone is the executor.


miler350 is correct - your params are constantly setting your assigner_id: current_user.id (looks like one of my suggestions).

The fix is to remove the .merge from your params & set it in your controller action (as per miler350's answer & like this):

#app/controllers/tasks_controller.rb
class TasksController < ApplicationController

    def new
        @task = Task.new
    end

    def create
        @task = Task.new task_params
        @task.assigner = current_user
        @task.save
    end

    def edit
        @task = Task.find params[:id]
    end

    def update
        @task = Task.find params[:id]
        @task.update task_params
    end

    private

    def task_params
        params.require(:task).permit(:executor_id, :name, :content, :deadline, :task_name_company, :assigner_id)
    end

end

By letting users "edit" an assignment, you should not have different assigner / executor defined each time.

Upvotes: 1

miler350
miler350

Reputation: 1421

def task_params
  params.require(:task).permit(:executor_id, :name, :content, :deadline, :task_name_company).merge(assigner_id: current_user.id)
end

You are setting the assigner id to current_user every time you pass in the params.

I would remove the merge, and just have strong params like this:

params.require(:task).permit(:executor_id, :name, :content, :deadline, :task_name_company, :assigner_id)

Then, in your create action, before you do:

@task.save

Add this:

@task.assigner_id = current_user.id

Then you can define your permissions however you choose (must be assigner, must be executor), but as long as you don't add anything crazy to update, it'll work fine.

Upvotes: 3

Related Questions