Rails: how to render nested form in table - ruby-on-rails

For example, I have two models:
class Task < ApplicationRecord
has_many :task_details
end
class TaskDetail < ApplicationRecord
belong_to :task
end
I want to display a table, each row in table is one TaskDetail and allow user input. After that user submits, all data will put to server. Here is my code:
(Note that: I #data[:task] is a task object because I want to return a hash with some information for view)
<%= form_for #data[:task], :url => tasks_path do |f| %>
<table> ... </table>
<% end %>
My question is: How can I do as my requirement.
thanks

Ensure that your Task model has accepts_nested_attributes_for :task_details and then you can do something like...
<%= form_for #data[:task], :url => tasks_path do |f| %>
<table>
<tr>
<th>Task Name</th>
<th>Task Description</th>
<tr>
<%= f.fields_for :task_details do |task_detail| %>
<tr>
<%= task_detail.hidden_field :id %>
<td><%= task_detail.text_field :name %></td>
<td><%= task_detail.text_field :description %> </td>
<tr>
<% end %>
</table>
<% end %>
Note the use of the hidden field for :id ... you need that so that rails can distinguish data from existing tasks versus a new task you're entering.
In your new method you should ensure there's at least one new task detail to provide an empty line on the form to input the detail
def new
...
#data[:task].task_details.build
...
end

Related

how can i get project_id by remarks in ruby on rails

I have manager remark model that takes input as a remark and decision value and saves it with the project site ID. I have a project site model that takes input as name, date, and file and stores it. Many remarks have a many to one relation with project site ID, and the project site belongs to the manager remark. I want to access the decision attribute boolean value in project site index form, but I am unable to access that boolean value in the index page of the project site. Here is my code of project site and manager remarks model, view and controller-
project site index.html.erb
<table>
<thead>
<tr>
<th>Name</th>
<th>Date</th>
<th>Attendance</th>
<th>Status</th>
<th colspan="3"></th>
</tr>
</thead>
<tbody>
<% #project_sites.each do |project_site| %>
<tr>
<td><%= project_site.name.titleize %></td>
<td><%= project_site.date %></td>
<td><%= link_to ' View attendance', project_site.file, :class => "fi-page-export-csv" %></td>
<td><%= "here i want to access manager remark decision value" %></td>
<td><%= link_to 'Remark ', project_site %><span>(<%= project_site.manager_remarks.size %>)</span></td>
<td><%= link_to 'Edit', edit_project_site_path(project_site) %></td>
<td><%= link_to 'Destroy', project_site, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</tbody>
project site controller
def index
#project_sites = ProjectSite.all.order("created_at DESC")
#manager_remark = ManagerRemark.joins(:project_site).where(:project_sites => { :user_id => #user.id })
end
# GET /project_sites/1
# GET /project_sites/1.json
def show
#manager_remark = ManagerRemark.new
#manager_remark.project_site_id = #project_site.id
end
# GET /project_sites/new
def new
#project_site = ProjectSite.new
end
def project_site_params
params.require(:project_site).permit(:name, :date, :file)
end
manager_remark controller
class ManagerRemarksController < ApplicationController
def create
#manager_remark = ManagerRemark.new(remark_params)
#manager_remark.project_site_id = params[:project_site_id]
#manager_remark.save
redirect_to project_site_path(#manager_remark.project_site)
end
def remark_params
params.require(:manager_remark).permit(:remark, :decision)
end
end
manager_remark view form
<%= form_for [ #project_site, #manager_remark ] do |f| %>
<div class="row">
<div class="medium-6 columns">
<%= f.radio_button :decision, true %>
<%= f.label :approve %>
<%= f.radio_button :decision, false %>
<%= f.label :reject %>
</div>
<br>
<br>
<div class="medium-6 cloumns">
<%= f.label :remark %><br/>
<%= f.text_area :remark %>
</div>
</div>
<div>
<%= f.submit 'Submit', :class => 'button primary' %>
</div>
<% end %>
routes.rb
Rails.application.routes.draw do
root to: 'home#index'
devise_for :users
resources :project_sites do
resources :manager_remarks
end
get '/project_manager_level_two' => 'project_manager_level_two#index'
get '/project_managers' => 'project_managers#index'
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
end
If I understand correctly, you have a ProjectSite that contains a ManagerRemark with a decision, right? If that's the case, the simple answer is:
<%= project_site.ManagerRemark.decision %>
If you are saying that each ProjectSite has many ManagerRemarks, you'll want to place the above inside a loop, like so:
<% project_site.manager_remarks.each do |manager_remark| %>
<%= manager_remark.decision %><br/>
<% end %>
This assumes that your models are correctly configured to recognize these relationships. The above may also be optimized by adding an include clause to your fetch inside the controller and there's no need to fetch the ManagerRemark objects separately. Therefore, you'd probably want something like:
def index
#project_sites = ProjectSite.all.includes( :manager_remark ).order("created_at DESC")
end

Error when trying to link to patient profile

I'm getting an error when trying to link_to a patient profile when a provider views his patients list. I have no problem displaying all the names of the patients that belong to the provider but when trying to link to the patient profile I get an undefined method 'id'.
So the way it works is, patients can search for providers and add them to the List model. On the provider side, I just list out all the patients that added that specific provider. Here is my erb code below,
<div class="body">
<div class="body">
<% if #active_patients.count > 0 %>
<table>
<thead>
<tr>
<th>Patient Name</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<% #active_patients.each do |list| %>
<tr>
<td>
<%= list.patient.role.user.first_name %> <%= list.patient.role.user.last_name %>
</td>
<td>
<%= link_to patient_path(id: #patient.id), class: "btn" do %>View<% end %> . #### THIS IS THE LINE
</td>
</tr>
<% end %>
</tbody>
</table>
<% else %>
<div class="no-records">
<%= image_tag "icon-no-records", class: "image" %>
<div class="text">You have no patients.</div>
</div><!--no-records-->
<% end %>
</div><!--body-->
</div>
Here is my List model,
class List < ApplicationRecord
belongs_to :membershipable, :polymorphic => true
belongs_to :provider
def patient
membershipable_type=='Patient' ? membershipable : nil
end
def provider_user
patient.try(:user)
end
end
Also here's the error message ->
Let Rails do the work of building the path. Each ActiveRecord model has a to_param method which decides how the instance will be encoded in an URL. By default it returns the model id but it could also be a slug based on the title or another property of the model.
Calling your helper like patient_path(patient) should do the trick.
Additionally, in your current code, you're referring to the previously unused #patient variable, even though it looks like you want to refer to list.patient instead.
Here:
<% #active_patients.each do |list| %>
<tr>
<td>
<%= list.patient.role.user.first_name %> <%= list.patient.role.user.last_name %>
</td>
<td>
<%= link_to patient_path(id: #patient.id), class: "btn" do %>View<% end %> . #### THIS IS THE LINE
</td>
</tr>
<% end %>
you have the variable list available to you. It appears that you get the patient by doing list.patient, as you do here:
<%= list.patient.role.user.first_name %> <%= list.patient.role.user.last_name %>
But, then you try to use a variable called #patient, here:
<%= link_to patient_path(id: #patient.id), class: "btn" do %>View<% end %> .
when you don't have the variable #patient. So, you get your nil error.
Instead, it seems you should do:
<%= link_to patient_path(id: list.patient.id), class: "btn" do %>View<% end %> .
Or, as milgner points out, you could simply do:
<%= link_to patient_path(list.patient), class: "btn" do %>View<% end %> .
Also, you might want to look into the Law of Demeter, which you violate (IMO) when you do:
list.patient.role.user.first_name

What Controls the Mapping of the Rails Controller Method to the View Rendered?

I have a rails application which is not routing as I expected. The search method in the controller is rending show. I've cut down the code to the minimal components and I am posting them here as suggested.
Rails.application.routes.draw do
resources :backups
get 'backups/search' => 'backups#search'
resources :components
resources :backup_media
end
class Component < ActiveRecord::Base
has_many :backups
has_many :backup_media, :through => :backups
end
class BackupMedium < ActiveRecord::Base
has_many :backups
has_many :components, :through => :backups
end
class Backup < ActiveRecord::Base
belongs_to :component
belongs_to :backup_medium
# value to match either the name of the component or backup_medium
def self.search(value)
tables = "backups, components, backup_media"
joins = "backups.backup_medium_id = backup_media.id and components.id = backups.component_id"
c = find_by_sql "select * from #{tables} where components.name like '%#{value}%' and #{joins}"
b = find_by_sql "select * from #{tables} where backup_media.name like '%#{value}%' and #{joins}"
c.count > 0 ? c : b
end
end
class BackupsController < ApplicationController
def search
#backups = Backup.search(params[:search])
render 'index'
end
def index
#backups = Backup.all
end
def show
# this would normally be the code to show an individual backup
# but I'm re-using the code from index because the routing is broken
#backups = Backup.all
end
end
views/backups/_search.html.erb
<%= form_tag backups_search_path, :method => 'get' do %>
<%= label_tag(:search, "Search for:") %>
<%= text_field_tag :search, params[:search], {:placeholder => 'Component or Media' }%>
<%= submit_tag "Search", :name => nil %>
<% end %>
views/backups/index.html.erb
<h1>Listing Backups</h1>
<p id="notice"><%= notice %></p>
<%= render :partial => 'search' %>
<table>
<tr>
<th>id</th>
<th>component_id</th>
<th>backup_medium_id</th>
</tr>
<% #backups.each do |backup| %>
<tr>
<td><%= backup.id %></td>
<td><%= backup.component.name %></td>
<td><%= backup.backup_medium.name %></td>
</tr>
<% end %>
</table>
views/backups/show.html.erb is copied from index.html.erb since it is incorrectly receiving the search results
<h1>Show Backup</h1>
<p id="notice"><%= notice %></p>
<%= render :partial => 'search' %>
<table>
<tr>
<th>id</th>
<th>component_id</th>
<th>backup_medium_id</th>
</tr>
<% #backups.each do |backup| %>
<tr>
<td><%= backup.id %></td>
<td><%= backup.component.name %></td>
<td><%= backup.backup_medium.name %></td>
</tr>
<% end %>
</table>
Suggestions on improving the search method will be welcomed.
As mentioned above, after the search is executed, the show.html.erb is rendered instead of search.html.erb
For a working demo (with better code thanks to suggestions here) see
https://github.com/pamh09/rails-search-demo
You do not have a backups_search_path in your routes, therefore it is treating search in the query string as an id and thus rendering show.html.erb, so try
get 'backups/search' => 'backups#search', as: :backups_search
In debugging I found that rails consistently routed to the wrong view when it was unhappy with the return object coming from the model.

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.

Create multiple records related to existing model

I'm a rails noob trying to develop a simple exercise log app, and I'm up against my limits. A user selects a category, and a specific workout, and I return a list of exercises belonging to that workout.
An effort is a user specific instance of an exercise.
class Exercise < ActiveRecord::Base
has_many :efforts
end
class Effort < ActiveRecord::Base
belongs_to :exercise
end
I'm retrieving the list of exercises in the efforts controller
class EffortsController < ApplicationController
def log_workout
#exercises = Exercise.where("category_id = ? AND workout_id = ?", params[:exercise][:category_id], params[:exercise][:workout_id])
#effort = Effort.new
end
end
My problem is that I'm not sure about my approach up to this stage. It does work so I have attempted to enable the user to log their workout by using a form like the following but I'm (not surprisingly) not getting the right info back from it and I'm not sure where to go with it...
<%= form_tag save_workout_path, method: :put do %>
<table>
<tr>
<th>Exercise</th>
<th>Sets</th>
<th>Reps</th>
</tr>
<%= #exercises.each do |exercise| %>
<%= fields_for "efforts[]", #effort do |f| %>
<tr>
<td><%= exercise.name %></td>
<td><%= f.number_field :sets %></td>
<td><%= f.number_field :reps %></td>
</tr>
<% end %>
<% end %>
</table>
<%= submit_tag "Log it" %>
<% end %>
If anybody has any thoughts/guidance/solutions I'd appreciate it

Resources