Reputation: 15
I have 4 models. Departments
, Courses
, Sections
, and Teacher
All of them are heirachically connected with the proper belongs_to
and has_many
relations. A section belongs to a course which belongs to a department. A teacher has many sections, however, a course has many (is taught by many different) teachers.
I would like to construct the site in such a way that the URL
/view/department_name/course_name/section_name/
shows the section with the name section_name
, which belongs to the course named couse_name
, which belongs to the department department_name
.
However, I also want to /view/teacher_name/course_name/section_name
to work the same way, where it shows all the sections associated with that teacher.
How can I do this?
FYI: the different models are connected by their IDs in the database. Section has a course_id integer associated with it, and course has a department_id integer. Section also has a department_id, which is redundant, but that's how I have it set up.
my routes.rb
Test2::Application.routes.draw do
resources :courses
resources :departments
resources :teachers
resources :sections
resources :courses
Upvotes: 0
Views: 274
Reputation: 16011
You mentioned things like section_name
in your routes. You should make sure the names are all URL-safe.
Another point you have to consider is the two paths you want is in fact quite similar and thus you may need to handle both in the same controller action.
/view/department_name/course_name/section_name
/view/teacher_name/course_name/section_name
The only different part is the department_name vs teacher_name. Hopefully there is no any teacher have the same name with your department XD"
You may define the path as:
get '/view/:department_or_teacher_name/:course_name/:section_name' => 'some_controller#some_action'
Then in your action, you need something like this:
def some_action
department_or_teacher = Department.find_by_name(params[:department_or_teacher_name]) || Teacher.find_by_name(params[:department_or_teacher_name])
course = Course.find_by_name(params[:course_name])
q = Section.where(name: params[:section_name]).where(course_id: course.id)
if department_or_teacher.class.name == "Department"
q = q.where(department_id: q.id)
elsif department_or_teacher.class.name == "Teacher"
q = q.where(teacher_id: q.id)
end
@section = q.first # I assume there should be only 1 section with a given name, under a specific course, and (under a specific department or a specific teacher)
end
The above generates 3 queries, which might not be very good. You may consider using joins:
def some_action
department_or_teacher = Department.find_by_name(params[:department_or_teacher_name]) || Teacher.find_by_name(params[:department_or_teacher_name])
q = Section.where(name: params[:section_name]).joins(:course).where("courses.name = ?", params[:course_name])
if department_or_teacher.class.name == "Department"
q = q.where(department_id: q.id)
elsif department_or_teacher.class.name == "Teacher"
q = q.where(teacher_id: q.id)
end
@section = q.first
end
There is still a difficulty in guessing the department or teacher. So if you redefine the path to something like this, the above could be cleaner:
get '/view/department/:department_name/:course_name/:section_name' => 'some_controller#some_action_for_department'
get '/view/teacher/:teacher_name/:course_name/:section_name' => 'some_controller#some_action_for_teacher'
def some_action_for_department
@section = Section.where(name: params[:section_name])
.joins(:course).where("courses.name = ?", params[:course_name])
.joins(:department).where("departments.name = ?", params[:department_name]) # you mentioned there is a department_id in sections, thus you could actually setup a belongs_to :department in section
.first
end
def some_action_for_teacher
@section = Section.where(name: params[:section_name])
.joins(:course).where("courses.name = ?", params[:course_name])
.joins(:teacher).where("teachers.name = ?", params[:teacher_name])
.first
end
This is the idea. I did not test it and just by guess. So please tell me if you encountered any problems.
Upvotes: 1