rails attribute changes in spite of not being in form - ruby-on-rails

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

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.

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.

Related

question id is not changing for user_choice

Here is my
question.controller
class QuestionsController < ApplicationController
def index
#questions = Question.all
end
def new
#question=Question.new
end
def create
#question=Question.new(question_params)
if #question.save
flash[:success] = "Question saved successfully"
redirect_to questions_url, notice: "Sucessfully created question"
else
render :new
end
end
private
def question_params
params.require(:mc_question).permit(:question, :option1, :option2, :option3, :option4, :answer)
end
# def result
# #question = Question.find(params[:id])
# #question.update(result_params) # not sure this is best way here, need to research a better way to create the nested resources rather than update
# end
# private
# def result_params
# params.require(:result).permit(result_attributes: [:user_choice, :question_id, :user_id])
# end
end
My result controller:
class ResultController < ApplicationController
def create
#result=Result.create(user_choice: params[:user_choice],
question_id: params[:question_id],
user_id: current_user.id)
end
end
My index for question and storing user_choice:
<div class="card o-hidden border-0 shadow-lg my-5">
<div class="card-body ">
<!-- Nested Row within Card Body -->
<div class="row py-5">
<div class="p-5">
<div class="text-center">
<h1 class="h4 text-gray-900 mb-4 ">Multiple-Choice Questions</h1>
</div>
<%= form_with model: #result ,url: result_path do |f| %>
<%= render "devise/shared/error_messages", resource: resource %>
<% #questions.each do |question| %>
<%= f.fields_for #questions do |fa|%> # with this i get nothing no error and no save
<%= fa.hidden_field :question_id, value: question.id %>
<%end%>
<%= f.hidden_field :user_id, value: current_user.id %>
<p><%= question.question %></p>
<% choices = [question.option1, question.option2, question.option3, question.option4] %>
<% choices.each do |c| %>
<div>
<%= f.radio_button :"user_choice[#{question.id}]", c %>
<%= f.label :user_choice, c %>
</div>
<%end%>
<% end %>
<div class="sub"> <%= f.submit "Submit", class:"btn btn-primary" %></div>
<% end %>
<div class="para1"><%= link_to 'New Question', new_question_path,class:"btn btn-primary btn-user" %>
</div>
</div>
</div>
</div>
</div>
</div>
With this
with this i get save everything but question id comes the last question id for every choice like if i have 12 questions then 12 will come for each choice
<%= fa.hidden_field :question_id, value: question.id %>
<%end%>
<%= f.hidden_field :user_id, value: current_user.id %>
I want a different id for each choice please help me if anyone knows what's the issue and how to solve it.
The reason you have that is because you have placed <%= fa.hidden_field :question_id, value: question.id %> inside of this loop <%= f.fields_for #questions do |fa|%> and it will populate using only one instance of your parent loop. Sort of like for i in 0...12 for j in 0...13 for every i instance, the j loop will run 13 times.
Long story short, do this
<% #questions.each do |question| %>
<%= fa.hidden_field :question_id, value: question.id %>
<%= f.hidden_field :user_id, value: current_user.id %>
<p><%= question.question %></p>
<% choices = [question.option1, question.option2, question.option3,
question.option4] %>
<% choices.each do |c| %>
<div>
.
.
.
.

check_box tied to the first element

I need to update value isCompleted in my model. But my code works only for todo item with id=1. If i click to another checkbox of todo item id remains the same (id=1). How to connect my checkbox for another items.
class TodosController < ApplicationController
def create
#todo = Todo.create(todo_params)
if #todo.save
redirect_to root_path
else
end
end
def update
#todos = Todo.find_by(params.require(:todos).permit(:id))
#todoo = #todos.update(bool)
redirect_to root_path
end
private
def todo_params
params.require(:todo).permit(:text, :project_id) # add any other attributes you want
end
def bool
params.require(:todos).permit(:isCompleted)
end
end
index.html.erb
<% #projects.each do |project| %>
<div class="col-md-6 col-lg-4">
<div class="todo">
<table>
<tr class="border_bottom">
<td>
<h2><%= project.title %></h2>
</td>
</tr>
<tr>
<td>
<ul>
<% project.todos.all.each do |todo| %>
<li>
<%= form_for :todos, :url => todos_update_path, method: :patch, html: {id: "update" } do |f| %>
<p>
<%=f.check_box(:isCompleted,{class: 'icheckbox_square-blue', checked: todo.isCompleted},todo.id) %>
<%= todo.text %>
<%= f.hidden_field :id, :value => todo.id %>
</p>
<% end %>
</li>
<% end %>
</ul>
</td>
</tr>
</table>
</div>
</div>
<% end %>
application.js
$(".icheckbox_square-blue").change( function(){
$('#update').submit();
you need to use a nested form. You have 2 Objects
Project has_many :todos
Then you need to build a form, form_for #project,
Query the todos in your projects#new
show all the todos children, f.fields_for :todos
read more at
http://guides.rubyonrails.org/form_helpers.html#nested-forms

Form_tag routing error after unsuccessful submit

I have an index page with a partial form to submit new records to Package model. I keep this form in the index page, so the user doesn't need to leave the page when repeating this action, several times.
In the same page I have a form_tag fir multiple updates for the same controller, namely packages_controller.
Everything works fine, except the following: when hit the update button, going to the form BUT instead of submitting I go back (with the browser) and try to select other records to be updated then I have a routing error:
Routing Error
No route matches [PUT] "/projects/47/orderlines/18/packages"
My index page looks like this:
<% if current_user %>
<%= render "packages/form" %>
<% end %>
<% if #packages.count >= 1 %>
<table class="table table-striped">
<thead>
<tr>
<th> <input type="checkbox" id="selectAll" value="selectAll"></th>
<th>Packed </th>
<th>#No.</th>
<th>Type</th>
<th>Gross weight</th>
<th>Length</th>
<th>Width</th>
<th>Height</th>
<th></th>
<th>Container</th>
</tr>
</thead>
<%= form_tag edit_multiple_project_orderline_packages_path, method: :get do %>
<tbody>
<% for package in #packages %>
<% if package.packed== true %>
<% #label_type="success" %>
<% else %>
<% #label_type="default" %>
<% end %>
<tr>
<td><%= check_box_tag "package_ids[]", package.id %></td>
<td><span class="label label-<%= #label_type %>"><% if package.packed==true %>Packed<% else %>Unpacked<% end %></span></td>
<td><%= package.package_no %></td>
<td><%= package.package_type %></td>
<td><%= package.gross_weight %></td>
<td><%= package.length %></td>
<td><%= package.width %></td>
<td><%= package.height %></td>
<% if #orderline.packages.count >= 1 %>
<td><%= link_to 'Delete', [package.orderline.project, package.orderline, package],
method: :delete,
data: { confirm: 'Are you sure?' } %></td>
<td><%= #containers.find(package.container_id).container_id if package.packed %></td>
<% end %>
</tr>
<% end %>
</tbody>
</table>
<%= submit_tag "Add to container", class: "btn btn-primary" %>
<% end %>
<br />
<%= will_paginate %>
<br>
And the multiple_edit form
<div class="col-sm-4">
<%= form_tag update_multiple_project_orderline_packages_path, method: :put do %>
<ul>
<% #packages.each do |package| %>
<li>
<%= hidden_field_tag "package_ids[]", package.id %>
<%= package.package_no %>
<%= package.container_id %>
<% package.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</li>
<% end %>
</ul>
<%= fields_for :package do |f| %>
<div class="field">
<%= f.label :package_no %><br />
<%= f.text_field :package_no, :class => "form-control" %>
</div>
<br />
<div class="field">
<%= f.label :container_id %><br />
<%= select_tag 'package[container_id]', options_from_collection_for_select(#project.containers, 'id', 'container_id', default_blank: true), prompt: "- Select container -", :class => "form-control" %>
</div>
<br />
<div class="field">
<%= f.label :packed %><br />
<%= f.select :packed, [["Packed", true], ["Unpacked", false]],{ prompt: "- Packing -"},{ :class => "form-control" } %>
</div>
<% end %>
<div class="actions">
<br />
<%= submit_tag "Update", :class => "btn btn-primary" %>
</div>
<% end %>
</div>
And the packages controller edit_multiple actions:
def edit_multiple
#project = Project.find(params[:project_id])
#packages = Package.find(params[:package_ids])
end
def update_multiple
#packages = Package.find(params[:package_ids])
#packages.reject! do |package|
package.update_attributes(package_params.reject { |k,v| v.blank? })
end
if #packages.empty?
redirect_to project_orderline_packages_url
else
#package = Package.new(package_params)
render "edit_multiple"
end
end
packages_controller create action:
def create
project = Project.find(params[:project_id])
orderline = project.orderlines.find(params[:orderline_id])
#package = orderline.packages.new(package_params)
#package.save
if #package.save
flash[:success] = "Package(s) was successfully added."
redirect_to :back
else
render 'new'
end
And my routes:
resources :projects do
resources :containers
resources :orderlines do
resources :packages do
collection do
put :packed
get :edit_multiple
put :update_multiple
end
end
end
end
I just added my routes here:
edit_multiple_project_orderline_packages_path GET /projects/:project_id/orderlines/:orderline_id/packages/edit_multiple(.:format)
packages#edit_multiple
update_multiple_project_orderline_packages_path PUT /projects/:project_id/orderlines/:orderline_id/packages/update_multiple(.:format)
packages#update_multiple
project_orderline_packages_path GET /projects/:project_id/orderlines/:orderline_id/packages(.:format)
packages#index
POST /projects/:project_id/orderlines/:orderline_id/packages(.:format)
packages#create
new_project_orderline_package_path GET /projects/:project_id/orderlines/:orderline_id/packages/new(.:format)
packages#new
edit_project_orderline_package_path GET /projects/:project_id/orderlines/:orderline_id/packages/:id/edit(.:format)
packages#edit
project_orderline_package_path GET /projects/:project_id/orderlines/:orderline_id/packages/:id(.:format)
packages#show
PATCH /projects/:project_id/orderlines/:orderline_id/packages/:id(.:format)
packages#update
PUT /projects/:project_id/orderlines/:orderline_id/packages/:id(.:format)
packages#update
DELETE /projects/:project_id/orderlines/:orderline_id/packages/:id(.:format)
your form_tag code is update_multiple_project_orderline_packages_path
I think it should be update_multiple_project_orderline_package_path(project_id, orderline_id, package_id)
I am not 100% sure with my statement above, because you gave scrambled Rails Routes, hard to read
and your form action seems goes to packages#edit_multiple controller
so paste your edit_multiple method, not create method
are you implementing your scenario above with javascript, or just plain HTML?

Nested Resource Rails

I have two models namely todo and tasks. Have set up a Has_many, Belongs_to assosciation between them (todo has many tasks, task belongs to todo).
I have set up a nested resource between them as shown below in my routes file
resources :todos do
resources :tasks
end
My form for creating new task is as shown below:
<%= form_for([#todo, #task], html:{class:'form-horizontal'}) do |f| %>
<% if #task.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#task.errors.count, "error") %> prohibited this todo from being saved:</h2>
<ul>
<% #task.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<script type="text/javascript">
$(document).ready(function () {
$('#datep').on('change', function () {
$('.datepicker').hide();
});
});
</script>
<div class="container">
<table style="width:70%" class="table">
<tr>
<td><%= f.label :title , "Task Title"%>
<%= f.text_field :title,:class=>'form-control input-sm' %></td>
</tr>
<tr>
<td><%= f.label :description,"Task Description"%>
<%= f.text_field :description,:class=>'form-control input-sm' %></td>
</tr>
<tr>
<td><%= f.label :deadline,"Task DeadLine"%>
<h id="datep"><%= f.text_field :deadline, :class=>'form-control input-sm', "data-provide" => "datepicker" ,"data-date-format" => "mm-dd-yyyy"%></h></td>
</tr>
<tr>
<td><%= f.label :assignee,"Task Assignee" %><br/>
<%= f.collection_select :assignee, User.all, :name, :name, {}, :class => "btn btn-default dropdown-toggle"%></td>
</tr>
<tr>
<td><%= f.label :tags,"Tags for Task"%>
<%= f.text_field :tags,:class=>'form-control input-sm' %></td>
</tr>
<tr>
<td><%= f.label :state,"Task Status"%><br/>
<%= f.select :state, ['Yet To Start', 'In Progress', 'Finished'], {}, :class => "btn btn-default dropdown-toggle"%></td>
</tr>
</table>
</div>
<br />
<div class="actions form-group">
<div class="container">
<%= f.submit 'Create New Task', class:'btn btn-success'%>
<%= link_to todos_path, class: 'btn btn-warning' do %>
<i class="glyphicon glyphicon-hand-left"></i> Back To List
<% end %>
</div>
</div>
<% end %>
My tasks controller code is shown below:
class TasksController < ApplicationController
def new
#task = Task.new
end
def create
#todo = Todo.find.(params[:todo_id])
#task = #todo.tasks.build(task_params)
if #task.save
redirect_to [#todo, #task]
else
redirect_to root_path
end
end
private
def set_todo
#todo = Todo.find(params[:todo_id])
end
def task_params
params.require(:task).permit(:assignee, :deadline, :state, :tags, :title, :description)
end
end
However when i want to add a new task to an particular todo i get this error saying
undefined method `tasks_path' for #<#<Class:0x007fd16a9c8810>:0x007fd169c95a80>
Did you mean? asset_path
Need help to know what am I doing wrong here???
redirect_to only accepts hash, record or string so this line redirect_to [#todo, #task] won't work. See http://api.rubyonrails.org/classes/ActionController/Redirecting.html. You can change it to redirect_to todo_tasks_path(#todo) which is reasonable here.
I also just noticed you didn't put before_filter :set_todo in the controller. You can remove #todo = Todo.find.(params[:todo_id]) in create action as it's no longer needed.
Hope it helps.

recipient checklist with text_area form

I am working on implementing a form where a user can compose a message and choose multiple recipients from a checklist in the same form.
I have already built and tested the messaging system which is working but now I want to create the proper form for my desired functionality.
When I use a multipart select form it works fine and looks like this.
<%= form_for #message do |f| %>
<div class="modal-body">
<%= f.text_area :body, class: "form-control"%>
</div>
<!-- displays the current users frinds their following -->
<%= f.select :user_tokens, #user.collect {|x| [x.name, x.id]}, {}, :multiple => true, class: "form-control" %>
<br>
<div class="modal-footer">
<%= f.button :submit, class: "btn btn-primary" %>
</div>
<% end %>
But I want to instead display the users in a checklist, this is what I have so far which displays everything with no errors, but dosent send messages.
<div class="results">
<%= form_tag new_message_path, method: 'get' do %>
<div class="modal-body">
<%= text_area :body, class: "form-control"%>
</div>
<table class="table-bordered">
<thead>
<tr>
<td class="col-md-1">Select</td>
<td class="col-md-1">User</td>
</tr>
</thead>
<% #user.each do |user| %>
<tbody>
<tr>
<td><%= radio_button_tag :user_tokens, user.id %></td>
<td><%= user.name %></td>
</tr>
</tbody>
<% end %>
</table>
<%= submit_tag "Send Message", :name => nil, class: "btn btn-primary" %>
</div>
<% end %>
</div>
Here is my controller
class MessagesController < ApplicationController
before_action :authenticate_user!
def new
#message = Message.new
#user = current_user.following
#users = User.all
end
def create
#message = current_user.messages.build(message_params)
if #message.save
flash[:success] = "Message Sent!"
redirect_to messages_path
else
flash[:notice] = "Oops!"
render 'new'
end
end
def index
#user = User.find(current_user)
#messages = Recipient.where(:user_id => #user).order("created_at DESC")
end
private
def message_params
params.require(:message).permit(:body, :sender_id, user_tokens: [])
end
end
My question is what is the best way to get this functionality?
Let me know if you need to see any other info, thanks.
I ended up figuring it out Thanks to this previous post I found, rails 3 has_many :through Form with checkboxes.
<%= form_for #message do |f| %>
<%= f.text_field :body %>
<p>
<% #user.each do |user| %>
<div>
<%= check_box_tag "message[user_tokens][]", user.id, #message.users.include?(user) %>
<%= user.name %>
</div>
<% end %>
</p>
<p><%= f.submit %></p>
<% end %>

Resources