I'd like to develop an app for schedule.
Each user create their own schedule.
I'd like to display the data as followings;
schedule title (user name)
day1(mm/dd,yyyy)
09:00 Math
11:00 Science
Room name A
day2(mm/dd,yyyy)
10:00 Physics
13:00 Music
Room name B
Although I can display the schedule title and user name, I couldn't display the date(mm/dd, yyyy) and room name. (I haven't make a model for course name and time)
It would be appreciated if you could give me any suggestion.
user.rb
class User < ActiveRecord::Base
has_many :schedlues
...
schedule.rb
class Schedule < ActiveRecord::Base
belongs_to :user
has_many :rooms
...
room.rb
class Room < ActiveRecord::Base
belongs_to :schedlue
schema
create_table "users", force: :cascade do |t|
t.string "name"
t.string "email"
...
end
create_table "schedules", force: :cascade do |t|
t.string "title"
t.integer "user_id"
...
end
create_table "rooms", force: :cascade do |t|
t.date "date"
t.string "room_name"
t.integer "schedule_id"
...
end
I haven't made a model for course name, time yet.
users_controller.rb
class UsersController < ApplicationController
def show
#user = User.find(params[:id])
#schedules = #user.schedules.paginate(page: params[:page])
end
...
show.html.erb
<% if #user.schedules.any? %>
<ol class="schedules">
<%= render #schedules %>
</ol>
<%= will_paginate #schedules %>
<% end %>
_schedule.html.erb
<li>
<span class="content"><%= schedule.title %>(<%= schedule.user.name %>)</span>
#Although I tried to display date and room name here, I couldn't.
</li>
You need to use has_many + through relationship over here.
See, a user has_many schedules, and one schedule has many rooms. So indirectly a user has_many rooms as well. You gotta write the following line of code in User model:
class User < ActiveRecord::Base
has_many :schedules
has_many :rooms, through: :schedules
end
Now, you can directly call rooms on a user object like following:
user = User.last
user.rooms.each do |room|
puts room.room_name # calling it simply `name` would be more appropriate.
end
Related
In my code, a user has students, a student has diaries, diaries have diary_entries. I want to show the diary entries of every student under the student show page. Below are my models.
Student.rb Model
class Student < ApplicationRecord
belongs_to :user
has_many :diaries, dependent: :destroy
has_many :teams, dependent: :destroy
has_many :subjects, dependent: :destroy
belongs_to :grade
accepts_nested_attributes_for :diaries
accepts_nested_attributes_for :subjects
accepts_nested_attributes_for :teams
end
Diary.rb Model
class Diary < ApplicationRecord
belongs_to :student
belongs_to :user
belongs_to :grade
has_many :diary_entries
validates :diary_year, presence: true
def self.from_student(owner, student_obj)
new(
user_id: owner.id,
student_id: student_obj.id,
grade_id: student_obj.grade_id,
diary_year: Date.today.year
)
end
end
Diary_entry.rb Model
class DiaryEntry < ApplicationRecord
belongs_to :diary
belongs_to :subject
belongs_to :user
validates :lesson_date, :assignment, :assignment_due_date, :notes_to_parents, presence: true
end
Diary Controller
class DiariesController < ApplicationController
before_action :authenticate_user!
before_action :set_student
def create
#diary = Diary.from_student(current_user, #student)
#diary.save
redirect_to #student, notice: "Diary was successfully created."
end
private
def set_student
#student = Student.find(params[:student_id])
end
end
Student controller #show
def show
#diary = #student.diaries
#diary_entries = #diary.diary_entries
end
Diary_entries controller #index and Show
def index
#diary_entries = #diary.diary_entries.all
end
def show
#diary_entry = DiaryEntry.find(params[:id])
end
I want each student to only have 1 diary per year, so I have added a diary_year column to each diary and then added a unique index for student_id and year on the diary table.
create_table "diaries", force: :cascade do |t|
t.bigint "user_id"
t.bigint "student_id"
t.bigint "grade_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "diary_year"
t.index ["grade_id"], name: "index_diaries_on_grade_id"
t.index ["student_id", "diary_year"], name: "index_diaries_on_student_id_and_diary_year", unique: true
t.index ["student_id"], name: "index_diaries_on_student_id"
t.index ["user_id"], name: "index_diaries_on_user_id"
end
Below is my attempted loop in the student show page.
<div class="card">
<div class="card-body">
<% #diary_entries.each do |entry| %>
<li><%= entry.assignment %></li>
<% end %>
</div>
</div>
I want to be able to 1. Get each student to have only 1 diary a year, 2. To show diary_entries under each students page.
You want to show diary_entries of Student, use joins
#diary_entries = DiaryEntry.joins(diary: :student)
.where(students: { id: #student.id })
More on joins - https://guides.rubyonrails.org/active_record_querying.html#joins
Give it a try!
Get each student to have only 1 diary a year,
To enforce one Diary object per year you could add a before_validation in the Diary model. See Callbacks
The callback should call a private function that checks for existing records that could conflict.
def ensure_valid_year
return unless student.diaries.where(diary_year: diary_year).any?
# code or function call here to handle rejection of the new Diary object
end
To show diary_entries under each students page.
You can add another relationship in the Student model.
has_many :diary_entries, through: :diaries
You can access the related DiaryEntry objects like so:
student1 = Student.first
student1.diary_entries
What I want to do is show the Users that are "pending" to join a Group. I have 3 models: Users, Membership, & Groups. I have enabled Users to be able to request to join a Group. When the request is made there is a attribute in the Membership model called "state" which I made the default value to be "pending". Once the Group Admin clicks accept then the User's state is changed to "active". How do I show only the Users that are in the "pending" state?
I am able to show all Users (both "pending" & "active") who request to join the Group by adding code "#members = #group.users" in the Group controller. When I wanted to show only the "pending" Users I created a method in model Group called "pending_members". This didn't work.
Currently I get an error message that says: "ActionView::MissingTemplate in Groups#show". The error message also highlights the code "<%= render #members %>". [When I use the code #members = #group.users then the webpage does show both "pending" & "active" Users]
Here are each of the Model attributes:
create_table "groups", force: :cascade do |t|
t.string "name"
end
create_table "memberships", force: :cascade do |t|
t.integer "user_id"
t.integer "group_id"
t.string "state", default: "pending"
end
create_table "users", force: :cascade do |t|
t.string "email"
t.string "first_name"
t.string "last_name"
end
Here is the code in each respective model:
class Membership < ActiveRecord::Base
belongs_to :user
belongs_to :group
end
class User < ActiveRecord::Base
has_many :memberships, dependent: :destroy
has_many :groups, through: :memberships
end
class Group < ActiveRecord::Base
has_many :memberships, dependent: :destroy
has_many :users, through: :memberships
end
Here is the code in the controller for Groups:
def show
#group = Group.find(params[:id])
#members = #group.pending_members
end
Here is the code in the model for Groups:
def pending_members
Membership.where(state: "pending")
end
Here is the code in the view for Groups/show.html.erb:
<div class="container">
<div class="row">
<%= render #members %>
</div>
</div>
If you want to show users in the pending state, then you pending_members method should return a collection of users. As it is it returns a collection of memberships.
You could write it like this:
def pending_members
User.includes(:memberships).where("memberships.state" => "pending)
end
then for your view to work you could put this in
<%= render partial: 'member', collection: #group.pending_members %>
Then you need to have in the app/views/groups directory the partial _member.html.erb which might look something like this:
<div id="user-<%= member.id %>">
<p>name: <%= member.first_name %> <%= member.last_name %></p>
<p>email: <%= member.email %></p>
</div>
In my Ruby on Rails application I am creating a cinema system, and on the bookings/new page I am allowing the user to choose the amount of seats they require through a drop down menu. But what I want to do is display the number of seats that are currently free in the screen, for example if a screen has 50 seats and 7 have been booked I want the system to display: "There are 43 seats available." I know I will need a method for this but am unsure about how I would implement it and how I would show this message.
It is worth noting that a seat would only be booked for one showing, so it would be free for others, which means that the method would have to be able to count the amount of seats available for that showing.
Can someone please help.
bookings/form.html.erb:
<%= form_for #booking do |f| %>
<%= f.hidden_field :user_id %>
<%= f.hidden_field :showing_id %>
<%= image_tag "thor_hammer.jpg",:size => "900x250" %>
<h1>NEW BOOKING:</h1>
<tr>
<td width="350px">
<br><%= f.label :seats_quantity, 'Please Select The Amount of Seats Required:' %>
</td>
<td width="300px">
<br><%= f.select :seats_quantity, '1'..'10' %><br>
</td>
<td width="300px">
<div class="actions">
<br><%= f.submit 'Book Showing' %>
</div>
<br><%= render "/error_messages", :message_header => "Cannot save: ", :target => #booking %>
</td>
</tr>
<% end %>
Screen.rb:
class Screen < ActiveRecord::Base
has_many :seats
has_many :showings
def screens_info
"#{name}"
end
end
Seat.rb:
class Seat < ActiveRecord::Base
belongs_to :screen
end
Booking.rb:
class Booking < ActiveRecord::Base
belongs_to :user
belongs_to :showing
end
Showing.rb:
class Showing < ActiveRecord::Base
belongs_to :film
has_many :bookings
belongs_to :screen
end
Schema:
create_table "bookings", force: :cascade do |t|
t.integer "user_id"
t.integer "showing_id"
t.integer "seats_quantity"
end
create_table "screens", force: :cascade do |t|
t.string "name"
end
create_table "showings", force: :cascade do |t|
t.date "show_date"
t.time "show_time"
t.integer "film_id"
t.integer "screen_id"
end
create_table "seats", force: :cascade do |t|
t.string "row_letter"
t.integer "row_number"
t.integer "screen_id"
end
It is worth noting that whilst the seats table contains the attributes row_letter and row_number a user IS NOT booking a specific seat, just the quantity of seats they require.
In your Screen class add:
has_many :bookings, through: :showings
And then your code becomes something like:
def remaining_seats
seats.count - bookings.sum(:seats_quantity) # <-- edited when I realized there was a quantity in a booking
end
def screens_info
"#{name} (#{remaining_seats}/#{seats.count} remaining)"
end
You need to figure out two values: the total seats for a specific showing and how many of those seats are already booked. Supposing you have two variables called scr_id and shw_id where the first represents the Screen Id and the second the Showing Id.
Total seats:
total_seats = Seat.where(screen_id: scr_id).count
Total bookings:
total_bookings = Booking.where(showing_id: shw_id).count
And then you only need to compute the differente between both.
available_seats = total_seats - total_bookings
EDIT: SPECIFIC IMPLEMENTATION
It should be implemented as a method in the screen model:
def available_seatings(shw_id)
total_seats = Seat.where(screen_id: this.id).count
total_bookings = Booking.where(showing_id: shw_id).count
return total_seats - total_bookings
end
Then in the controller
#available_seatings = screen.available_seatings(shw_id)
You can then use the #available_seatings variable in the view
EDIT
The manual way of doing this would be like so:
class Showing < ActiveRecord::Base
def booked_seats
bookings.pluck(:seats_quantity).sum
end
def available_seats
seats.count - booked_seats
end
end
OLD
This looks like a good use of Rails' counter_cache.
class Booking < ActiveRecord::Base
belongs_to :showing, counter_cache: true
end
This will store the count in a column on the Showing model (which you have to add). Then when you do #showing.bookings.size (not count), it will refer to that column.
"With this declaration, Rails will keep the cache value up to date, and then return that value in response to the size method." http://guides.rubyonrails.org/association_basics.html
I have a Contract model that has_many Task_Orders. I am trying to render a view where if I click "Show" for Contract line item, it will display a list of Task_Orders that belong to that Contract.
Here is my Contract schema:
create_table "contracts", force: true do |t|
t.string "contractId"
t.string "contractName"
Here is my Task Order schema:
create_table "task_orders", force: true do |t|
t.integer "contract_Id", limit: 255
t.string "task_orderId"
t.string "task_orderName"
Here is my Contract model:
class Contract < ActiveRecord::Base
has_many :task_orders
end
Here is my Task Order model:
class TaskOrder < ActiveRecord::Base
belongs_to :contract
end
I am not entirely sure how to work with the controller and view to make it happen.... please help. I am using Rails 4.0
Thank you.
foreign_key
Firstly, you need to ensure your foreign_keys are assigned for your associations:
#app/models/task_order.rb
Class TaskOrder < ActiveRecord::Base
belongs_to :contract, primary_key: "contractID", foreign_key: "contract_Id"
end
#app/models/contract.rb
Class Contract < ActiveRecord::Base
has_many :task_orders, primary_key: "contractID", foreign_key: "contract_Id"
end
--
Controller
This should allow you to call the required data from your controller:
#app/controllers/contracts_controller.rb
Class ContractsController < ApplicationController
def show
#contract = Contract.find params[:id]
end
end
#app/views/contracts/show.html.erb
<% for order in #contract.task_orders do %>
<%= order.id %>
<% end %>
Can not call my associate table in my view. have tried this. it is an application that only adds to the players. after the press "start game" and then he should come to the result view where the results of all players. then I will of course have the name of the "players" table and then the binding results from the "results" table. now in quire, I enter bidningen in the background as long as
view:
<% #playersname.each do |p|%>
<ul>
<li><%= p.name %></li>
<li><%= p.results.try(:result) %></li>
</ul>
<%end%>
Controller:
class ResultsController < ApplicationController
def index
#playersname = Player.all
end
end
Model:
class Result < ActiveRecord::Base
# attr_accessible :title, :body
has_many :players
end
migration:
class CreateResults < ActiveRecord::Migration
def change
create_table :results do |t|
t.string "result", :limit => 40
t.string "cal", :limit => 40
t.string "sum",:limit => 300
t.timestamps
end
end
end
The CreateResults migration miss the player_id column.
Do belongs_to :player in your Result class and correct the migration (or do another one).
[Edit] I wasn't clear enough : I think you inverted the relationship logic.
You actually did the "one result has several players".
I suppose you want that a player has several results ?
class Player
has_many :results
end
class Result
belongs_to :player
end
So you can do :
#myplayer = Player.all.first
#myplayer.results #it is an array of player's results
#myplayerresult = #myplayer.results.first
puts #myplayerresult.result
If you want a one-to-one relationship, consider replacing has_many :results by has_one :result and so you can do #myplayer.result to get your result.