Nested Resource Rails - ruby-on-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.

Related

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?

Ruby On Rails Basic Show method failed still

In this block of code, i want to put a button "edit" inside the "show" views. However, due to some reason, it did not works out
My home_controller.rb
class HomeController < ApplicationController
def index
#inputs = Person.all
end
def new
#input = Person.new
end
def create
#input = Person.new(input_params)
respond_to do |x|
if #input.save
x.html {redirect_to :action => 'index'}
else
x.html {render :action => 'new'}
end
end
end
def show
#input = Person.find(params[:id])
end
def edit
#input = Person.find(params[:id])
end
def update
#input = Person.find(params[:id])
respond_to do |x|
if #input.update(input_params)
x.html {redirect_to :action => 'index'}
else
x.html {render :edit}
end
end
end
private
def input_params
params.require(:inputs).permit(:name, :weight, :height, :color, :age)
end
end
My routes file only have two lines:
resources: home
root 'home#index'
My index.html.erb
<p id="notice"><%= notice %></p>
<h1>Listing</h1>
<table>
<thead>
<tr>
<th>Name</th>
<th> Weight</th>
<th> Height</th>
<th> Color</th>
<th> Age</th>
<th colspan="3"></th>
</tr>
</thead>
<tbody>
<% #inputs.each do |person| %>
<tr>
<td><%= person.name %></td>
<td><%= person.weight %></td>
<td><%= person.height %></td>
<td><%= person.color %></td>
<td><%= person.age %></td>
<td><%= link_to 'Show',home_path(person.id) %></td>
<td><%= link_to 'Edit', edit_home_path(person.id) %></td>
</tr>
<% end %>
</tbody>
</table>
<br>
<%= link_to 'New Test', new_home_path %>
my show.html.erb:
<p>
<strong>Name:</strong>
<%= #input.name %>
</p>
<p>
<strong>Weight:</strong>
<%= #input.weight %>
</p>
<p>
<strong>Height:</strong>
<%= #input.height %>
</p>
<p>
<strong>Color:</strong>
<%= #input.color %>
</p>
<p>
<strong>Age:</strong>
<%= #input.age %>
</p>
<% link_to 'Edit', edit_home_path(#input) %>
<%= link_to 'Back', home_index_path%>
My form.html.erb
<%= form_for #input, url: {action: "update"} do |person| %>
<div class="field">
<%= person.label :name %><br>
<%= person.text_field :name %>
</div>
<div class="field">
<%= person.label :weight %><br>
<%= person.number_field :weight %>
</div>
<div class="field">
<%= person.label :height %><br>
<%= person.number_field :height %>
</div>
<div class="field">
<%= person.label :color %><br>
<%= person.text_field :color %>
</div>
<div class="field">
<%= person.label :age %><br>
<%= person.number_field :age %>
</div>
<div class="actions">
<%= person.submit %>
</div>
<% end %>
My edit.html.erb
<h1>Editing Data</h1>
<%= render 'form' %>
<%= link_to 'Show', home_path %> |
<%= link_to 'Back', home_index_path %>
The error i get is:
My code <% link_to 'Edit', edit_home_path(#input) %> is point the Edit button to the route home/edit with the obeject #input, that is how i understand it, but it still not working.
Any idea how can i fix this?
Many thanks
The problem is in your show.html.erb. You need to change #person to #input as you have #input defined in your show method

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
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.

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 %>

form not creating new entries

I am trying to create a form to add a transporter:
I have app/views/transporters/new.html.erb that calls a template,app/views/_form.html.erb that looks like:
<%= form_for(#transporter) do |f| %>
<% if #transporter.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#transporter.errors.count, "error") %> prohibited this transporter from being saved:</h2>
<ul>
<% #transporter.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :name %><br>
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :phone %><br>
<%= f.text_field :phone %>
</div>
<div class="field">
<%= f.label :id_number %><br>
<%= f.text_field :id_number %>
</div>
<div class="actions">
<%= f.submit 'Add transporter', class: 'btn btn-success' %>
</div>
<% end %>
<%= link_to 'Back to all transporters', transporters_path, class: "btn" %>
</div>
</div>
This is the create action in my transporters controller:
def create
#transporter = Transporter.new(transporter_params)
end
private
def transporter_params
params.require(:transporter).permit(:name, :phone, :id_number)
end
When I click Add transporter the form doesn't go anywhere. What do I have wrong?
Update:
this is my routes file:
Cowsnhills::Application.routes.draw do
resources :transporters
resources :deliveries
root 'welcome#index'
end
When I click submit the form reloads but the entries will not show on my transporters index, here is that code:
transporters controller method:
def index
#transporters = Transporter.all
end
and transporters index:
<h1>Listing transporters</h1>
<table>
<thead>
<tr>
<th>Name</th>
<th>Phone</th>
<th>Id</th>
<th></th>
<th></th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<% #transporters.each do |transporter| %>
<tr>
<td><%= transporter.name %></td>
<td><%= transporter.phone %></td>
<td><%= transporter.id %></td>
<td><%= f.link_to_add "Add a delivery", :deliveries %></td>
<td><%= link_to 'Show transporter details', transporter %></td>
<td><%= link_to 'Edit transporter details', edit_transporter_path(transporter) %></td>
<td><%= link_to 'Delete transporter', transporter, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</tbody>
</table>
<br>
<%= link_to 'New Transporter', new_transporter_path, class: "btn" %>
Also there's a transporter has_many deliveries and a velivery belongs_to transporter association going on
You just create a new object with your params from the form in your create action, but you don't save it.
add #transporter.save to your create action.
use
#transporter = Transporter.new(params[:transporter])
or
#transporter = Transporter.new(params["transporter"])
check my last comment to save it.

Resources