Reputation: 457
I have a list of classrooms that belong_to a school and a school has_many classrooms. I have users who belong to a school and fill out a form of information. On this form I have the following selector:
Pins/_form.html.erb
<div class="form-group">
<%= label_tag(:classroom, "Select your classroom:") %>
<%= select_tag "pin[code]", options_from_collection_for_select(Classroom.all, "code", "code", ) %>
</div>
Right now this form shows all the classrooms listed in the data base. I need it to show just the classrooms that belong to the school. Classrooms have a name and a code, the code is what ties the students form submission to that classroom.
I'm still learning RoR and have struggled to figure this type of problem one out on a couple of occasions.
Here's the Classroom Controller
class ClassroomsController < ApplicationController
before_action :set_classroom, only: [:show, :edit, :update, :destroy]
after_action :verify_authorized
respond_to :html
def home
@classrooms = Classroom.all
respond_with(@classrooms)
authorize @classrooms
end
def index
@classrooms = Classroom.all
respond_with(@classrooms)
authorize @classrooms
end
def show
respond_with(@classroom)
end
def new
@school = School.find(params[:school_id])
@classroom = @school.classrooms.new
@teachers = @school.teachers
respond_with(@classroom)
flash[:notice] = "Classroom created."
authorize @classroom
end
def edit
end
def create
@school = School.find(params[:school_id])
@classroom = @school.classrooms.new(classroom_params)
@classroom.save
respond_with @school
authorize @classroom
end
def update
@classroom.update(classroom_params)
respond_with([@school,@classroom])
end
def destroy
@classroom.destroy
redirect_to @school
flash[:notice] = "You have succesfully deleted the classroom."
end
private
def set_classroom
@classroom = Classroom.find(params[:id])
@school = School.find(params[:school_id])
authorize @classroom
end
def classroom_params
params.require(:classroom).permit(:teacher_id, :name, :code)
end
end
Pins_controller
class PinsController < ApplicationController
before_action :set_pin, only: [:show, :edit, :update, :destroy]
respond_to :html
def show
respond_with(@pin)
end
def new
@pin = Pin.new
@emotions = Emotion.all
@causes = Cause.all
@school = School.find(params[:school])
@classrooms = @school.classrooms
respond_with(@pin)
authorize @pin
end
def edit
end
def create
code = params[:pin][:code]
@classroom = Classroom.where('code LIKE ?', code).first
unless @classroom
flash[:error] = "Classroom code incorrect"
@emotions = Emotion.all
@causes = Cause.all
render :new
else
params[:pin][:classroom_id] = @classroom.id
@pin = Pin.new(pin_params)
@pin.save
params[:pin][:cause_ids].each do |cause_id|
@cause = Cause.find(cause_id)
@pin.causes << @cause
end
params[:pin][:emotion_ids].each do |emotion_id|
@emotion = Emotion.find(emotion_id)
@pin.emotions << @emotion
end
if @pin.save
redirect_to signout_path and return
end
respond_with(@pin)
authorize @pin
end
end
def update
@pin.update(pin_params)
respond_with(@pin)
authorize @pin
end
def destroy
@pin.destroy
respond_with(@pin)
authorize @pin
end
private
def set_pin
@pin = Pin.find(params[:id])
authorize @pin
end
def pin_params
params.require(:pin).permit(:user_id, :question, :question1, :question2,
:question3, :question4, :question5, :classroom_id, :sad,
:happy, :mad, :brave, :embarrassed, :sorry, :frustrated,
:silly, :left_out, :excited, :hurt, :jealous, :confused,
:proud, :other)
end
end
School.rb model
class School < ActiveRecord::Base
has_many :users
has_many :classrooms
validates_uniqueness_of :code
def classrooms
self.users.classrooms
end
def students
self.users.students
end
def teachers
self.users.teachers
end
def admins
self.users.admins
end
end
User Model
class User < ActiveRecord::Base
devise :timeoutable, :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_many :pins
has_many :reflections
has_many :classrooms, :foreign_key => :teacher_id
belongs_to :school
validates :name, presence: true
validates :role, presence: true
# validates :school, presence: true
scope :students, -> { where(role: "student") }
scope :teachers, -> { where(role: "teacher")}
scope :teachers_and_admins, -> { where(:role => ["teacher", "admin"]) }
scope :admins, -> { where(role: "admin" ) }
scope :online, lambda{ where("updated_at > ?", 15.days.ago) }
def online?
updated_at > 15.days.ago
end
def admin?
role == "admin"
end
def teacher?
role == "teacher"
end
def student?
role == "user" || role == "student"
end
def superadmin?
role == "superadmin"
end
def admin_of_school?(school)
self.admin? && self.school == school
end
def teacher_of_school?(school)
self.teacher? && self.school == school
end
def admin_or_teacher_of_school?(school)
self.admin_of_school?(school) || self.teacher_of_school?(school)
end
end
classroom model
class Classroom < ActiveRecord::Base
belongs_to :school
belongs_to :teacher, :class_name => "User"
has_and_belongs_to_many :users
has_many :pins
has_many :reflections
validates_presence_of :school
validates_presence_of :teacher
validates :code, :uniqueness => { :scope => :school_id }
end
I found a similar answer here: Rails only give records that "belong_to"
But it didn't help me understand how to limit the drop down list to only Classrooms of the current school.
Any ideas on how to handle his situation?
Upvotes: 0
Views: 41
Reputation: 42789
You already select the school in the controller, so just use it in the view, instead of doing a Classroom.all
do a @school.classrooms
<%= select_tag "pin[code]",
options_from_collection_for_select(@school.classrooms, "code", "code")
%>
First the User model can stay as it is
class User < ActiveRecord::Base
#devise place holder
# assocciations
has_many :pins
has_many :reflections
has_many :classrooms, foreign_key: :teacher_id
belongs_to :school
#validations place holder
#scopes
scope :students, -> { where(role: "student") }
scope :teachers, -> { where(role: "teacher")}
scope :admins, -> { where(role: "admin" ) }
scope :teachers_and_admins, -> { teachers.admins }
scope :online, -> { where("updated_at > ?", 15.days.ago) }
# some check methods
end
classroom class
class Classroom < ActiveRecord::Base
belongs_to :school
belongs_to :teacher, ->{ User.teachers }, class_name: 'User'
has_many :pins
has_many :reflections
end
school class
class School < ActiveRecord::Base
has_many :users
has_many :admins, ->{ User.admins }, class: User
has_many :students, ->{ User.students }, class: User
has_many :teachers, ->{ User.teachers }, class: User
has_many :classrooms
end
Now the controllers
You need to clean up the duplications, so here's an example from ur pins#new
action
def new
@pin = Pin.new
prepare_lookups
respond_with(@pin)
authorize @pin
end
def prepare_lookups
@emotions = Emotion.all
@causes = Cause.all
@school = School.find(params[:school])
@classrooms = @school.classrooms
end
I removed the common code to a separate method, and call it whenever i need, of course you can add or remove from that method according to your needs.
Anyways, I think you should read more about active record assocciations and the conventions in writing controller actions
Upvotes: 1