CS计算机代考程序代写 Rapid Application Development

Rapid Application Development
COSC2675 2021 Week 8
A/Prof. Andy Song andy.song@rmit.edu.au
Before Week 7
• REST
• RESTfulresources(withdifferentformats)
• RESTfulmethods
• Multiple tables
• Association methods
• Dependent tables
A/Prof. Andy Song RMIT University 2021
2

Many-to-Many
• What about the relationship between students and courses?
• Students and courses do not belong to each other.
• Howevertherealotofconnectionsbetweenthem.
• Firstly we need deal with the models.
• Then update the controllers.
• Then the views.
• Railsprovidesaverygoodfoundation.
• But we still need to add a lot.
• Warning: don’t name a table “classes” otherwise you might experience many Rails disasters because of name conflicts.
A/Prof. Andy Song RMIT University 2021
3
Create Tables
• Creating a course table is not enough. We need additional table that joins courses and students.
$ rails generate scaffold course name:string
• Thejointablerequiresafewtables.Firstlycreateamigration $ rails generate migration CreateCoursesStudents
It created a file
db/migrate/[time_stamp]_create_courses_students.rb
class CreateCoursesStudents < ActiveRecord::Migration[5.2] def change create_table :courses_students do |t| end end A/Prof. Andy Song RMIT University 2021 4 Coding the migration • Wehavereachedtheboundariesofcodeauto-generation. • Need to write the migration class CreateCoursesStudents < ActiveRecord:: Migration def change create_table :courses_students, id: false do |t| t.integer :course_id, null: false t.integer :student_id, null: false end end end • Rails naming conventions is the key here. • Thetablenameisthecombinationoftwojoiningmodelsin alphabetical order. • Thefieldswithinthetableareidvaluesforeachofthemodels A/Prof. Andy Song RMIT University 2021 5 Coding the migration... • create_table method is a ActiveRecord method. See API http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatem • ents.html#method-i-create_table create_table(table_name, comment: nil, **options) create_table(:books) do |t| t.column :name, :string, limit: 80 end create_table(:books) do |t| # with shorthand t.string :name, limit: 80 end create_table(:books) add_column(:books, :name, :string, {limit: 80}) The option hash include keys like :id, :primary_key, :temporary, :force, :as :id Whether to automatically add a primary key column. Defaults to true. Join tables for ActiveRecord::Base.has_and_belongs_to_many should set it to false. • A/Prof. Andy Song RMIT University 2021 6 Index in join table • Railsuseidvaluefortablestoimproveperformance,sodatacan be processed rapidly. • The id value is automatically indexed. • To use your own index, you can add this method in migration: add_index :courses_students, [:course_id, :student_id], unique: true • add_index method’s API documentation can be read here: http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatem ents.html#method-i-add_index add_index(table_name, column_name, options = {}) • Now run the migration $ rails db:migrate A/Prof. Andy Song RMIT University 2021 7 Connecting the Models • Add the many-to-many relationship to app/models/student.rb has_and_belongs_to_many :courses • Add the many-to-many relationship to app/models/course.rb has_and_belongs_to_many :students • That’sallforestablishingtheconnection • Thanks to Rails naming conventions. • Nowtablecourses_studentscankeeptrackoftheconnections. • Note: has_and_belongs_to_many can be controversial; some developers may prefer has_many :through relationship, by creating an intermediate table. A/Prof. Andy Song RMIT University 2021 8 Connecting the Models ... (Learning Rails 5, Mark Locklear Eric Gruber) A/Prof. Andy Song RMIT University 2021 9 Methods which may be useful • app/models/student.rb to check whether a student is enrolled? def enrolled_in?(course) self.courses.include?(course) end def unenrolled_courses Course.all - self.courses end • Remember the minus – operator operating on arrays? A/Prof. Andy Song RMIT University 2021 10 Controllers • Controllersformany-to-manyaresimplerthannestedresources. However we may need some supporting methods. • app/controllers/courses_controller.rb to add after destroy # GET /courses/1/roll def roll @course = Course.find(params[:id]) end # What is this for? • app/controllers/students_controller.rb # GET /students/1/courses def courses @student = Student.find(params[:id]) @courses = @student.courses end A/Prof. Andy Song RMIT University 2021 # What is this for? 11 Add course method # POST /students/1/course_add?course_id=2 def course_add #Convert ids from routing to objects @student = Student.find(params[:id]) @course = Course.find(params[:course]) unless @student.enrolled_in?(@course) #add course to list using << operator @student.courses << @course flash[:notice] = 'Student was successfully enrolled' else flash[:error] = 'Student was already enrolled' end redirect_to action: "courses", id: @student end A/Prof. Andy Song RMIT University 2021 12 Remove course method def course_remove #Convert ids from routing to object @student = Student.find(params[:id]) #get list of courses to remove from query string course_ids = params[:courses] if course_ids.any? course_ids.each do |course_id| course = Course.find(course_id) if @student.enrolled_in?(course) logger.info "Removing student from course #{course.id}" @student.courses.delete(course) flash[:notice] = 'Course was successfully deleted' end end end redirect_to action: "courses", id: @student end 13 A/Prof. Andy Song RMIT University 2021 Routing Update the routing: config/routes.rb resources :courses resources :students resources :courses do member do get :roll end end resources :students do member do get :courses post :course_add post :course_remove end end A/Prof. Andy Song RMIT University 2021 14 Now the Views A/Prof. Andy Song RMIT University 2021 15 Making the Views • Create app/views/application/_navigation.html.erb • Write the navigation partial

<%= link_to "Students", students_path %> |
<%= link_to "Courses", courses_path %>


• Add this partial to app/views/layouts/application.html.erb

<%= render 'navigation' %>
<%= yield %>
• Student views
Add course to student list app/views/students/index.html.erb
Table head, insert before Awards

Courses

Table body, insert before Awards

<%= student.courses.count %>

16
A/Prof. Andy Song RMIT University 2021



More work on the views…
Course view app/views/courses/index.html.erb Table head, insert after (course) name

Enrolled

Table body, insert after course name

<%= course.students.count %>

Students show app/views/students/show.html.erb
Add the course enrollment info

Courses: <% if !@student.courses.empty? %>
<%= @student.courses.collect {|c| link_to( c.name, c)}.join(",").html_safe %>
<% else %>
Not enrolled on any courses yet.
<% end %>

Insert another link in between Edit and Back
<%= link_to 'Courses', courses_student_path(@student) %> |
A/Prof. Andy Song RMIT University 2021
17
Courses in students views
• Create app/views/students/courses.html.erb

<%= @student.name %>‘s courses

<% if @courses.length > 0 %>
<%= form_tag( course_remove_student_path(@student)) do %>

<% for course in @courses do %>

<% end %>

Course Remove?
<%= course.name %> <%= check_box_tag "courses[]", course.id %>
A/Prof. Andy Song RMIT University 2021
18

Courses in students views…
• In app/views/students/courses.html.erb
<%= submit_tag 'Remove checked courses' %> <% end %>
<% else %>

Not enrolled in any courses yet.

<% end %>

Enroll in new course

<% if @student.courses.count < Course.count then %>
<%= form_tag( course_add_student_path(@student)) do %> <%= select_tag(:course, options_from_collection_for_select (@student.unenrolled_courses, :id, :name)) %>
<%= submit_tag 'Enroll' %> <% end %>
<% else %>

<%= @student.name %> is enrolled in every course.

<% end %>

<%= link_to 'Back', @student %>

A/Prof. Andy Song RMIT University 2021
19
• •
Courses views…
In app/views/courses/show.html.erb Insert another link in between Edit and Back
<%= link_to 'Roll', roll_course_path(@course) %> |
Create app/views/courses/roll.html.erb

Roll for <%= @course.name %>

<% if @course.students.count > 0 %>

<% @course.students.each do |student| %>

<% end %>

Student GP
<%= link_to student.name, student %> <%= student.grade_point_average %>
<% else %>

No students are enrolled.

<% end %>
A/Prof. Andy Song RMIT University 2021
20

Viewing the Roll
• Localhost:3000/courses/[x]/roll
A/Prof. Andy Song RMIT University 2021
21
Nested Resources
• Students and awards aren’t really parallel, not like students and courses. That dependency can be better modeled.
• Manually changeconfig/routes.rb resources :awards
resources :students
resources :students do
resources :awards
end
• The students page http://…../students is OK. However the
awards page http://…../awards is no longer working.
• Accessing the awards page needs to go through students like
http://…../students/1/awards/2
A/Prof. Andy Song RMIT University 2021
22

Implementing nested awards
• Changing the controller is a bit complicated.
• Mainly to add student as context in AwardsController.
before_action :set_award, only: [:show, :edit, :update, :destroy]
before_action :get_student
before_action :set_award, only: [:show, :edit, :update, :destroy]
Method index: Method new:
Method create:
@awards = Award.all
@awards = @student.awards @award = Award.new(award_params)
@award = @student.awards.new
@award = Award.new(award_params)
@award = @student.awards.new(award_params)
format.html { redirect_to @award, notice: ‘Award..’} format.html { redirect_to student_awards_url(@student),
A/Prof. Andy Song RMIT University 2021
23
Implementing nest awards…
Method update: if @award.update(award_params)
if @award = @student.awards.update( award_params)
format.html { redirect_to @award, notice: ‘Award..’} format.html { redirect_to student_awards_url(@student),
Method destory: format.html { redirect_to @award, notice: ‘Award..’} format.html { redirect_to student_awards_url(@student),
Private methods:
Method set_award: @award = Award.find(params[:id])
@award = @student.awards.find(params[:id]) Add method get_student
def get_student
@student = Student.find(params[:student_id])
end
A/Prof. Andy Song RMIT University 2021
24


Change the views for awards
Update app/views/awards/index.html.erb

Awards

Awards for <%= @student.name %>

<% if !@student.awards.empty? %>
<%# the whole table body here .... then the else %>
<% else %>

<%= @student.given_name %> has no awards yet.

<% end %>
Inside the table:

<%= link_to 'Show', award%> <%= link_to 'Show', [@student, award] %> <%= link_to 'Edit', edit_award_path(award) %> <%= link_to 'Edit', edit_student_award_path(@student, award) %>

A/Prof. Andy Song RMIT University 2021

25
Change the views for awards …
• Inside the table in app/views/awards/index.html.erb

<%= link_to 'Destroy', award, method: :delete, <%= link_to 'Destroy', [@student, award], ............. • Afterthetable: <%= link_to 'New Award', new_award_path %>
<%= link_to 'New Award', new_student_award_path(@student) %> | <%= link_to 'Back', @student %>
26

More views to change (show)
• Also need to change app/views/awards/show.html.erb <%= link_to 'Edit', edit_award_path(@award) %>
| <%= link_to 'Back', awards_path %>
<%= link_to 'Edit', edit_student_award_path(@student, @award) %> | <%= link_to 'Back', student_awards_path(@student) %>
A/Prof. Andy Song RMIT University 2021
27

More views to change (new)
Also need to change app/views/awards/new.html.erb

New Award

<%= render 'form', award: @award %>
<%= link_to 'Back', awards_path %>

New Award for <%= @student.name %>

<%= render 'form', award: @award %>
<%= link_to 'Back', student_awards_path(@student) %>
• Changethefirstlineofpartialapp/views/awards/_form.html.erb <%= form_with(model: award, ...) do |form| %>
<%= form_with(model: [@student, award], ...) do |form| %> • Deletethestudentselectorfromtheform
A/Prof. Andy Song RMIT University 2021
28

More views to change (new) …
• Create is viewable at https://…students/[x]/awards/new
A/Prof. Andy Song RMIT University 2021
29
More views to change (edit)
• Change app/views/awards/edit.html.erb

Editing Award

Editing Award for <%= @student.name %>

<%= link_to 'Show', @award %> | <%= link_to 'Back', awards_path %>
<%= link_to 'Show', [@student, @award] %> |
<%= link_to 'Back', student_awards_path(@student) %>
A/Prof. Andy Song RMIT University 2021
30

Connecting the student views
• Change app/views/students/show.html.erb
<%= link_to 'Edit', edit_student_path(@student) %> |
<%= link_to 'Back', students_path %>
• <%= link_to 'Edit', edit_student_path(@student) %> | <%= link_to 'Awards', student_awards_path(@student) %> | <%= link_to 'Back', students_path %>
A/Prof. Andy Song RMIT University 2021
31
• •
Connecting the student views…
Change app/views/students/index.html.erb

Add behind the edit link

<%= link_to 'Awards', student_awards_path(student) %>

A/Prof. Andy Song RMIT University 2021
32

Is Nesting Worth It?
• Itwasalotofwork!!
• However it is the “right” approach in Rails.
• It makes the has_many/belongs_to relationship explicit on every level, not just in the model
• Routing and controllers are updated so both the web interface and the RESTful web services interface work in nested way.
• Whether to use nesting depends on the application. For the award example, general users may want easy navigation so nesting is better. For an admin, direct interface might be better.
• Ifyouaregoingtonestresources,doitearly.
• Nestedresourcesmayrequireadditionalinterfaces. A/Prof. Andy Song RMIT University 2021
33
Summary
• Many-to-many
• Join tables
• Many-to-many controllers
• Many-to-many views
• Nested resources
A/Prof. Andy Song RMIT University 2020
34