Editing multiple records in one form - Rails - ruby-on-rails

I'm trying to edit multiple records using one form, so the user can edit a few records then press submit at the end rather than after each individual one. I've posted my current code, and I get this error:
undefined method `connection_connection_path'
Controller
def show
#customer = Customer.find(params[:id])
#connection = #customer.connections
respond_to do |format|
format.html # show.html.erb
format.json { render json: #customer }
end
end
View
<table class="table">
<thead>
<th>Interface</th>
<th>Device</th>
<th>Speed</th>
<th>Site</th>
<th>Capable</th>
<th>Notes</th>
</thead>
<%= form_for(#connection) do |f| %>
<% #connection.each do |l| %>
<tr>
<td><%= l.interface %></td>
<td><%= l.device %></td>
<td><%= l.speed %></td>
<td><%= l.site.name%> </td>
<td><%= f.check_box :check %></td>
<td><%= f.text_field :notes %></td>
</tr>
<% end %>
<tr><%= f.submit %></tr>
</table>
<% end %>
routes
resources :connections
resources :sites
resources :customer_sites
resources :customers
root :to => "customers#index"

so where is your submit button?? and it should not done in show, maybe you might create a new method in your controller and do the multiple edit function.
The basic concept is when you have checks, you need to pass an array of your object to your method, and update them one by one. or you can do that using JS as well.
refer this railscast
http://railscasts.com/episodes/165-edit-multiple
and this stackoverflow
Rails 3 Edit Multiple Records in a Single Form
these resources you can get easily by google :D
if still have problem, just come and ask here again

Related

Facing issues with link_to "Edit" in rails

I am trying to display all the metrics in a table format with an edit option. But, I end up with the below error
In Index view, I am able to see all the data. But when I click on edit link, it is not redirecting to edit view where I have different columns to be showed.
index view:
<%= form_for :metrics_controller, url: metrics_path(#metric), method: :get do |f| %>
<table id="metrics">
<thead>
<tr id="AllMetricColumnNames">
<th id="CommentsColumn">Comments</th>
<th id="EditColumn">Edit</th>
</tr>
</thead>
<% #metricAll.each do |data| %>
<tr id="AllMetricValues">
<td id="Comments"><%= data.Comments %></td>
<td id="EditButton"><%= link_to "Edit", edit_metric_path(#metricAll) %></td>
<% end %>
</tr>
</table>
<% end %>
Controller:
class MetricsController < ApplicationController
def index
#metricAll = Metric.all
end
def show
#metric = Metric.find(params[:id])
end
def edit
#metric = Metric.find(params[:id])
end
private def post_params
params.require(:metric).permit(:Metric, :Comments)
end
end
routes:
root 'metrics#index'
get 'index' => 'metrics#index'
get 'edit' => 'metrics#edit'
resources :metrics
You're passing ALL the metrics for the edit route. Move from
<td id="EditButton"><%= link_to "Edit", edit_metric_path(#metricAll) %></td>
to
<td id="EditButton"><%= link_to "Edit", edit_metric_path(data) %></td>
data is the current metric in your code
According to your screenshot, the error is within the model.
Also, as mentioned by others, you should remove those get routes as the resources :metrics will generate the necessary routes for all your CRUD actions a.ka. for the index, show, edit, new, create, update, destroy.
My guess is that the metric.rb file has a belongs_to :automated_thresholding relationship but the metrics database table is missing the field automated_thresholding_id.
You should create a migration to add that field
add_reference :metrics, :automated_thresholding

ruby on rails Insert Multiple record in a table using form with no relationship

I am building a timesheet project. i want to insert multiple records depending on the count of projects allocated to employes.
the problem is how to insert multiple records into in a table using forms
For example is the image i was trying to do:
code for form is
<%= form_for(:timesheets, :url => {:action => 'create',:employee_id => #pro.id}) do |d| %>
<% if !#project.nil? %>
<% #project.each do |page| %>
<tr>
<%= d.hidden_field("employee_id" ,:value => #pro.id) %>
<%= d.hidden_field("project_id" ,:value => page.id) %>
<% if !page.employee_id.blank? %>
<td><%= page.prog_name %></td>
<td><%= d.text_field("IN",:class => "qty1") %></td>
<td><%= d.text_field("comments") %></td>
<% end %>
</tr>
<% end %>
<% end %>
<tr>
<td>Total hours</td>
<td colspan="2"><%= text_field_tag("total")%></td>
</tr>
<tr border="0">
<td><%= submit_tag("Submit") %></td>
<td colspan="2" border="0"></td>
</tr>
<% end %>
Your question is really vague, but I think I get what you're asking. I had to build a similar form recently, and used a form object with a row class, with an instance of the row class being initialized for every record that needed to be added.
See this for an introduction to form objects if you're not familiar already: http://blog.codeclimate.com/blog/2012/10/17/7-ways-to-decompose-fat-activerecord-models/
class TimesheetForm
# include ActiveModel stuff here
# attr_reader :projects, ...
# validations for form as a whole, if desired
def initalize(employee)
#employee = employee
#projects = employee.projects
end
def submit(params)
# extract params and create new instances of TimesheetForProject for each set of timesheet params
# run validations on all #timesheet_rows
# persist if all validations pass
end
class TimesheetForProject
# validations for each timesheet record
def initialize(project)
#project = project
end
# timesheet-specific form logic
end
end
This doesn't contain a lot of details you need, but it's a rough conceptual outline of a pattern I've seen and used to solve this type of problem.

Rails 4 Restaurant order system ActiveRecord::RecordNotFound in ItemsController#create

I am creating a simple restaurant ordering system with a one to many relationship between a menu and its items. One menu has many items. For the sake of simplicity it is not a many to many.
I am able to create menus fine, but would like to be able to add and show the menu items for that menu in the menus show action.
The menu show action displays okay but when I try to add a new menu item I get the following error:
ActiveRecord::RecordNotFound in ItemsController#create
Couldn't find Menu with 'id'=
raise RecordNotFound, "Couldn't find #{name} with '#{primary_key}'=#{id}"
And here is the queries from the terminal:
Started POST "/items" for ::1 at 2015-01-11 16:09:44 +0000
Processing by ItemsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"***", "item"=>{"name"=>"Test", "price"=>"23", "course"=>"Main", "vegetarian"=>"1", "allergy"=>""}, "commit"=>"Add item"}
Menu Load (0.3ms) SELECT `menus`.* FROM `menus` WHERE `menus`.`id` = NULL LIMIT 1
Completed 404 Not Found in 8ms
EDIT: I followed doon's advice and looked into nested resources and this is indeed a better way of doing it. The updated code is below:
routes.rb
resources :menus do
resources :items
end
menus_controller.rb
def show
#menu = Menu.find(params[:id])
#items = #menu.items
end
items_controller.rb
def create
#menu = Menu.find(params[:menu_id])
#item = #menu.items.create!(item_params)
if #item.save
flash[:success] = "Item added!"
redirect_to #menu
else
flash[:danger] = "Errors found!"
redirect_to #menu
end
end
private
def item_params
params.require(:item).permit(:name, :price, :course, :vegetarian, :allergy, :menu_id)
end
And the Menus
show.html.erb
<%= link_to "<< Back", menus_path, data: { confirm: back_message } %>
<h1><%= #menu.name %> menu</h1>
<center><button id="toggleButton" class="btn btn-sm btn-info">Show/Hide Add Item Form</button></center>
<br>
<div class="row">
<div class="col-xs-offset-3 col-xs-6 toggleDiv hideDiv">
<%= form_for [#menu, Item.new] do |f| %>
<table class="table table-condensed table-no-border">
<tr>
<th scope="row" class="col-xs-2">Name:</th>
<td class="col-xs-10"><%= f.text_field :name %></td>
</tr>
<tr>
<th scope="row">Price:</th>
<td><%= f.text_field :price %></td>
</tr>
<tr>
<th scope="row">Course:</th>
<td><%= f.select(:course, options_for_select([['Starter', 'Starter'], ['Main', 'Main'], ['Dessert', 'Dessert'], ['Drink', 'Drink']]), prompt: "Please select...", class: 'form-control') %></td>
</tr>
<tr>
<th scope="row">Vegetarian:</th>
<td><%= f.check_box :vegetarian %></td>
</tr>
<tr>
<th scope="row">Allergy:</th>
<td><%= f.text_field :allergy %></td>
</tr>
<tr><td colspan="2"><%= f.submit "Add item", class: "btn btn-sm btn-success col-xs-offset-4 col-xs-4" %></td></tr>
</table>
<% end %>
</div>
</div>
<table class="table table-condensed">
<thead>
<tr>
<th>Name</th>
<th>Price</th>
<th>Course</th>
<th>Vegetarian</th>
<th>Allergy</th>
</tr>
</thead>
<tbody>
<% #items.each do |item| %>
<tr>
<td><%= item.name %></td>
<td><%= number_to_currency(item.price, unit: "£") %></td>
<td><%= item.course %></td>
<td><%= item.vegetarian %></td>
<td><%= item.allergy %></td>
</tr>
<% end %>
</tbody>
</table>
What I would probably do in a case like this (especially if your item doesn't exist outside of a menu) is to use Nested Resources:
http://guides.rubyonrails.org/routing.html#nested-resources
http://railscasts.com/episodes/139-nested-resources (a bit dated, but still a decent grounding)
Below are some changes to get you pointed in this direction.
config/routes.rb
resources :menu do
resources :items
end
now our urls will look like
/menu/:menu_id/items/
So we need to adjust the items_controller to get the menu by looking at :menu_id, and we don't need the hidden field anymore. I put it in a before_action as every method in the controller will build through the association.
items_controller.rb
class ItemsController < ApplicationController
before_action :find_menu
...
def create
#item = #menu.items.new(item_params)
if #item.save
redirect_to #menu, notice: 'item added'
else
redirect_to #menu, warning: 'item failed'
end
end
...
private
def find_menu
#menu = Menu.find(params[:menu_id])
end
end
if you want to show it on the menu, we need a new Item to display.
menus_controller.rb
def show
#menu = Menu.find(params[:id])
#item = #menu.items.new
end
Then we need to make use of the nested resource in the menus/show view. By passing in the array of the menu and the item, rails will generate the correct path.
menus/show.html.erb
<%= form_for [#menu,#item] do |f| %>
Are you posting to "/post" or "post/[:id]"?
#menu = Menu.find(params[:id])
Will not find anything if you do not pass it an id. The id can come from the URL params, but this means you should be sending your request to "/post/[:menuid].
You can use the gem https://github.com/charliesome/better_errors to debug your program at the controller level and execute rails console there. just put in "fail" in your controller and then you will have a command line interface where you can inspect your params value and ensure it has the id included and play with the console there.
I have now solved it. Thanks to better_errors I was able to better understand what was going on.
I implemented the show action in menus_controller.rb from aaron.
def show
#item = Item.new
#menu = Menu.includes(:items).find(params[:id])
end
I needed a way to pass the menu id into the menu_id field, so I added a hidden field in the table or show.html.erb passing the current #menu.id into the :menu_id field.
<%= f.hidden_field :menu_id, :value => #menu.id %>
I have read online that passing values through hidden fields is not a great idea though.
Then in the create action of the Items Controller I was able to make a new record as usual redirecting to the existing show view using the menu id from the item object.
def create
#item = Item.new(item_params)
if #item.save
redirect_to menu_path(#item.menu_id)
else
redirect_to menu_path(#menu.menu_id)
end
end
It feels like a bit of a hack so open to suggestions on how to improve.

DRYing code resulted in doubling output

I am making a resume application to list my employment history, education history and other responsibilities. This is my first rails application on my own without a tutorial, but much of what I do is just following the same actions. All the code is here: https://github.com/victorman/portfolio
Quick summary. I ajaxed my app a bit, and got it to work. But I had a template with the exact same html as part of a view, so I replaced that portion with a render :partial.... The result was twice the html as before. Below is a more detailed description of what I did to the app.
I made two scaffolds, one for Jobs and one for Categories. Jobs has a foreign key to categories.
I made the Jobs view list a link for each category. The jobs#index controller then only finds the rows in the jobs table for that category.
Then I decided to throw some ajax in there so that clicking a link would only reload the relevant data. I added a respond_to at the end of the jobs#index method.
def index
#find which jobs to display based on category_id in the url params
#if no category_id param is given default to 1
unless params.has_key? :category_id
#jobs = Job.find(:all, :conditions => {:category_id => 1})
else
#jobs = Job.find(:all, :conditions => {:category_id => params[:category_id]})
end
respond_to do |format|
format.html
format.js #index.js.erb
end
end
I made a index.js.erb file that retrieves the new data and replaces the old.
var jobs = $("<%= escape_javascript(render(:partial => #jobs))%>").hide();
$("#jobs_table").replaceWith(jobs);
$("#jobs_table").fadeIn();
I added remote: true to the links in the jobs index.html.erb file.
<ul>
<% Category.all.each do |category| %>
<li><%= link_to category.name, { :controller => "jobs", :category_id => "#{category.id}" }, :class => "category_link", remote: true %></li>
<% end %>
</ul>
And I made the template partial where the jobs were displayed. it would never find _jobs.html.erb so i had to name it _job.html.erb
<tbody id="jobs_table">
<% #jobs.each do |job| %>
<tr>
<td><%= job.organization %></td>
<td><%= job.location %></td>
<td><%= job.details %></td>
<td><%= job.start_date %></td>
<td><%= job.end_date %></td>
<td><%= link_to 'Show', job %></td>
<td><%= link_to 'Edit', edit_job_path(job) %></td>
<td><%= link_to 'Destroy', job, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</tbody>
after all that it worked but I still hadn't DRY'd up the code so I removed the repeated section from index.html.erb which is in _job.html.erb (as shown above) and replaced it with this.
<%= render :partial => #jobs %>
and now it gives me two identical <tbody> tags with id="jobs_table". Why is this giving duplicate data?
You've got a lot to fix...
Create a nested route in your routes.rb:
resources :jobs
resources :categories do
resources :jobs
end
index.html.erb:
<h1>Listing jobs</h1>
<div>
<ul>
<% Category.all.each do |category| %>
<li><%= link_to category.name, category_jobs_path(category),
class: "category_link", remote: true %></li>
<% end %>
</ul>
</div>
<table>
<thead>
<tr>
<th>Organization</th>
<th>Location</th>
<th>Details</th>
<th>Start date</th>
<th>End date</th>
<th></th>
<th></th>
<th></th>
</tr>
</thead>
<tbody id="jobs_table"><%= render partial: #jobs %></tbody>
</table>
<br/>
<%= link_to 'New Job', new_job_path %>
the index of jobs_controller.rb can (should) be refactored to:
class JobsController < ApplicationController
def index
#jobs = Job.where(category_id: params[:category_id] || 1)
respond_to do |format|
format.html
format.js
end
end
end
and the index.js.erb response also should be refactored to:
$("#jobs_table").html("<%= escape_javascript(render partial: #jobs) %>")
$("#jobs_table").fadeIn()
there are some naming issues which should be more pregnant like:
jobs instead of jobs_table
and
category instead of category_link
Also trying to find a Job belonging to Category with 1 is odd. Deal with a different response than a default Category with id 1 (hard coded ids are one of the worst things you can do).
The div around the Categories list is useless (keep your rendered HTML slim and readable).
The problem is due to not understanding when rails manipulates singular vs plural.
Calling render partial: #jobs automagically goes out to the partial _job.html.erb for each element in #jobs. But then the partial goes through each element again because of #jobs.each do |job|.
To fix it, in the render line, replace #jobs with "jobs" and rename _job.html.erb to _jobs.html.erb.
Alternatively, save a step by just replacing #jobs with "job" and keep the template name _job, but this reinforces an incorrect naming scheme.
index.html.erb:
<tbody id="jobs"><%= render partial: "jobs" %></tbody>
index.js.erb:
$("#jobs").html("<%= escape_javascript(render(partial: 'jobs'))%>")
Now it will just search literally for the _jobs template (_jobs.html.erb) and render it once as opposed to going to the singular version of the name and rendering that many times.

My controller is -persistently- sending wrong params[:id] in Rails?!

I'm new to Ruby on Rails & to web programming.
In my application I have two models; Directorate which has_many :users, and User which belongs_to :directorate.
When creating a new user, I use <%= f.collection_select(:directorate_id,Directorate.all, :id, :name) %> in the new.html.erb form to assign the new user to specific directorate. However, I want to build a user-friendly interface for the dba that lists all directorates; and listing all users beside each directorate, with a link to assign any user to a specific directorate.
What I did is the following:
In Directorate model, I defined the following function:
def assign_user!(user)
user.update_attributes(directorate_id: #directorate)
end
and in the directorates controller, I defined the following action:
def assign_user
#directorate = params[:directorate]
assign_user! params[:user]
redirect_to directorates_url
end
Now, directorates/index.html.erb contains the following:
<h1>Listing directorates</h1>
<table>
<tr>
<th>Name</th>
<th>Info</th>
</tr>
<% #directorates.each do |directorate| %>
<tr>
<td><%= directorate.name %></td>
<td><%= directorate.info %></td>
<td><%= link_to 'Show', directorate %></td>
<td><%= link_to 'Edit', edit_directorate_path(directorate) %></td>
<td><%= link_to 'Destroy', directorate, confirm: 'Are you sure?', method: :delete %></td>
<%= #directorate = directorate%>
<%= render 'users_form' %>
</tr>
<% end %>
</table>
<br />
<%= link_to 'New Directorate', new_directorate_path %>
and, -users_form.html.erb contains the following form (which is supposed to list all users beside each directorate, with a link to assign any user to a certain directorate):
<h1>Listing Users</h1>
<table>
<tr>
<th>User Name</th>
</tr>
<% #users.each do |user| %>
<tr>
<td><%= user.username %></td>
<td><%= link_to 'Assign to Current Directorate', {controller: 'directorates', action: 'assign_user', directorate: #directorate, user: user}, :method => :put %></td>
</tr>
<% end %>
</table>
<br />
Here is the problem, when listing directorates & click on the 'Assign to Current Directorate' I receive the following error:
http://127.0.0.1:3000/directorates/assign_user?directorate=4&user=5
ActiveRecord::RecordNotFound in DirectoratesController#update
Couldn't find Directorate with id=assign_user
Rails.root: /home/ehab/sites/IAMS
Application Trace | Framework Trace | Full Trace
app/controllers/directorates_controller.rb:61:in `update'
Request
Parameters:
{"_method"=>"put",
"authenticity_token"=>"L5tz3hv2IW0meE79qUq0/tjfGKwDlpC23hOeAWtmTvk=",
"directorate"=>"4",
"user"=>"5",
"id"=>"assign_user"}
It's clear that the params is submitting "id"=>"assign_user" which I don't want, what i want is "id"=>"directorate.id" (4 in the above example). What shall I do to fix this issue?!
first of all your routes should say that assign_user is a member method on a certain directorate object:
resources :directorates do
member do
put :assign_user
end
end
second you say you define assign_user! in Directorate model and assign_user in DirectoratesController but both methods imply that they share same object state like instance variable #directorate which is not true
your controller method assign_user should look vaguely like
def assign_user
#directorate = Directorate.find params[:id]
#user = User.find params[:user_id]
#directorate.assign_user! #user
end
and model method should look like
def assign_user!(user)
user.update_attributes(directorate_id: self.id)
end
and even that i would switch around to instead of telling Directorate to change user's attributes you would tell User to assign itself to whatever controller wants.
and the final bit is your link that assigns user to directorate:
link_to 'Assign to Current Directorate',
assign_user_directorates_path(#directorate, :user_id => user)
0 lines of code above were tested for even syntactical correctness, DO NOT copy-paste, read and understand

Resources