I am new to Rails and I am struggling on something which sounds easy but can not get it to work. I have two models Students and Attendances.
Student model:
name lastname classroom_id
Attendance model:
present:boolean absent:boolean halfday:boolean attnd_date:date student_id
Students has_many :attendances and attendance belongs_to :student.
I can make an entry for individual student and take their attendance however I want to generate a view where I show all the students (or show all students for a given classroom) and next to each student name I would like to show the three checkboxes so that I can mark who is present and absent in one go rather than one by one and submit the form.
Any help here is much appreciated. Using Rails 4 and ruby 2.2.0
Thanks
You can make an edit action, where you will find the classroom for which you want to mark attendances.
class AttendancesController < ApplicationController
def edit
#classroom = Classroom.find(<classroom-id>)
end
def update
end
end
In your view edit.html.erb
<%= form_for(#classroom, url: '/attendances/:id', method: :put) do |f| %>
<table>
<%- #classroom.students.each do |student| %>
<tr>
<td><%= student.name %></td>
<td><%= checkbox_tag "attendances[#{student.id}][present]" %></td>
<td><%= checkbox_tag "attendances[#{student.id}][absent]" %></td>
<td><%= checkbox_tag "attendances[#{student.id}][halfday]" %></td>
</tr>
<% end %>
</table>
<%= f.submit %>
<% end %>
This way, when you submit the form, you will receive these params in your update action:
`{ attendances: { '1' => { present: false, absent: true, halfday: false }, '2' => { present: true, absent: false, halfday: false }, ... } }`.
Then you can write logic in your action to save these details to database.
Note: This is kind of pseudo code. Please check the syntax and options for different html tags.
Thanks to #Jagdeep Singh for getting me up and running. I have now made the process more simple so I can get my head around. I just want to get the list of all students and create their attendances.
My view:
<% #students = Student.all %>
<%= form_for(:attendances, url: '/admin/attendances/') do |f| %>
<table>
<%= #today %>
<th>Name</th><th>Present</th><th>Absent</th><th>halfday</th>
<%- #students.each do |student| %>
<tr>
<td><%= student.first_name %></td>
<td><%= check_box_tag "attendances[#{student.id}][present]" %></td>
<td><%= check_box_tag "attendances[#{student.id}][absent]" %></td>
<td><%= check_box_tag "attendances[#{student.id}][halfday]" %></td>
</tr>
<% end %>
</table>
<%= f.submit %>
<% end %>
when I click on create attendance button it just creates just one with record with all default params and.
I am sorry I am still learning but once I get my head around on how I can create attendances for all 10 students i have in one go.
Related
Hi I want to put a link in a index table of a resource to create a child resource.
I got a Sale, and an operation:
class Sale < ApplicationRecord
belongs_to :user
has_one :operation, dependent: :destroy
end
class Operation < ApplicationRecord
belongs_to :sale
end
And I want to be able to create an operation through an index table of sales.
Thing is, I need it to be created on the button/link click, and not be transferred to a new operation view. (Operation has only sale_id and id as attributes)
Something like that
<table>
<tr>
<th>Sale Id</th>
</tr>
<% #sales.each do |sale| %>
<td><%= sale.id %></td>
<td><%= link_to 'Show', sale_path(sale) %></td>
<td><%= link_to 'Edit', edit_sale_path(sale) %></td>
<td><%= link_to 'Delete', sale,
method: :delete,
data: { confirm: 'Are you sure?' } %></td>
<td> <%= form_for (#operation) do |o| %>
<%= o.submit 'Create Operation'%>
<% end %>
</td>
</tr>
<% end %>
</table>
But I got this error: 'First argument in form cannot contain nil or be empty'
I also tried this:
<td>
<%= fields_for :operation, #sales.operation do |o| %>
<%= o.submit "Create Operation" %>
<% end %>
</td>
And I got this:
undefined method `operation' for Sale::ActiveRecord_Relation:0xb1a4ece4>
tried this as well :
<td>
<%= link_to 'Create Operation', 'operations#create' %>
</td>
But it sends me to the operation index view without creating an operation.
First argument in form cannot contain nil or be empty
The error means #operation is nil in the form. You should define #operation in the sales#index method as the form is in sales/index.html.erb
def index
#operation = Operation.new
end
I need it to be created on the button/link click, and not be
transferred to a new operation view
If you meant,you shouldn't be redirected to another view after the button, then you have to use AJAX. I recommend you see these Guides to understand how to do with AJAX
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.
In my application, I am grouping my objects by an ID. At the moment, I can only display the ID, but I would like to display the attribute value.
A Fixture belongs_to a tournament and a tournament has_many fixtures.
Controller
def index
#fixtures = Fixture.all
#tournament_fixture = #fixtures.group_by {|f| f.tournament_id}
end
View
<% #tournament_fixture.sort.each do |tourn_name, fixture| %>
<%= tourn_name %>
<% fixture.each do |f| %>
<td><%= f.home_team %></td>
<td><%= f.away_team %></td>
<td><%= f.kickoff_time %></td>
</tr>
<% end %>
<% end %>
How can I get
<%= tourn_name %>
to display its corresponding value that is in its :name column?
At the moment in my view for example i get this returned
<tbody>
2
<tr>
<td>Tournament Name</td>
<td>Team 1</td>
<td>Team 2</td>
<td>2000-01-01 14:00:00 UTC</td>
<td><a class="btn btn-success" href="/fixtures/1">view</a></td>
</tr>
</tbody>
The 2 needs to be the value in the :name column
I'd recommend grouping by tournament instead:
#tournament_fixture = #fixtures.group_by(&:tournament)
And then iterate using:
<% #tournament_fixture.sort.each do |tournament, fixture| %>
<%= tournament.name %>
...
<% end %>
You can access the whole object much like you can get the id like this:
def index
#fixtures = Fixture.includes(:tournaments).all
#tournament_fixture = #fixtures.group_by {|f| f.tournament.name}
end
The id is still available as either f.tournament_id or f.tournament.id, should you still need it but I just figured you'd rather group by its name directly. I simply added an includes statement to also load the referenced Tournament objects with your fixtures in one go. Otherwise, Rails would load the tournaments only when you access them one by one.
As an alternative, you could load the Tournaments, including all their the fixtures instead and iterate over the tournaments like this:
Controller
def index
#tournaments = Tournament.includes(:fixtures).all
end
View
<% #tournaments.each do |tournament| %>
<%= tournament.name %>
<% tournament.fixtures.each do |f| %>
<td><%= f.home_team %></td>
<td><%= f.away_team %></td>
<td><%= f.kickoff_time %></td>
</tr>
<% end %>
<% end %>
It seems a bit more natural to me and you don't need to iterate over all fixtures to map them by their tournament.
You can load the fixtures in the right order. There is no need to group then in memory. Remember to include the tournaments to avoid N+1 queries.
# controller
def index
#fixtures = Fixture.order(:tournament_id).includes(:tournaments).all
end
Loading in the right order in the controller makes the view simpler. For the tournament's name just use the association between Fixture and Tournament.
# view
<% #fixtures.each do |fixture| %>
<tr>
<td><%= fixture.tournament.name %></td>
<td><%= fixture.home_team %></td>
<td><%= fixture.away_team %></td>
<td><%= fixture.kickoff_time %></td>
</tr>
<% end %>
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
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