Controller for classrooms and students The actions I'm wondering about are members, add_student, and remove_student.  They work just fine, but they aren't RESTful and it feels like they should be handled (perhaps) by the StudentsController.

Note that members and show are the same. The only difference is that the members.html.erb view iterates over and displays @classroom.students while show.html.erb displays info about the classroom itself.

class ClassroomsController &lt; ApplicationController

  # GET /classrooms
  def index
    @classrooms = Classroom.all.order('name ASC')
  end

  # GET /classrooms/1
  def show
    @classroom = Classroom.find(params[:id])

    authorize @classroom
  end

  # GET /classrooms/1/members
  def members
    @classroom = Classroom.find(params[:id])

    authorize @classroom
  end

  # GET /classrooms/new
  def new
    @classroom = Classroom.new
    @classroom.build_avatar

    authorize @classroom
  end

  # GET /classrooms/1/edit
  def edit
    @classroom = Classroom.find(params[:id])
    @classroom.build_avatar unless @classroom.avatar

    authorize @classroom
  end

  # POST /classrooms
  def create
    @classroom = Classroom.new(classroom_params)

    authorize @classroom

    if @classroom.save
      redirect_to classrooms_path, notice: 'Classroom was successfully created.'
    else
      render action: "new"
    end
  end

  # PUT /classrooms/1
  def update
    @classroom = Classroom.find(params[:id])

    authorize @classroom

    if @classroom.update(classroom_params)
      redirect_to edit_classroom_path(@classroom), notice: 'Classroom was successfully updated.'
    else
      render action: "edit"
    end
  end

  def add_student
    @classroom = Classroom.find(params[:id])
    @student = Student.find(params[:classroom][:student_ids][0])

    authorize @classroom

    @classroom.students &lt;&lt; @student

    respond_to do |format|
      @count = @classroom.students.count
      format.js
    end
  end

  def remove_student
    @classroom = Classroom.find(params[:id])
    @student = Student.find(params[:classroom][:student_ids][0])

    authorize @classroom

    @classroom.students.delete(@student)

    respond_to do |format|
      @count = @classroom.students.count
      format.js
    end
  end

  # DELETE /classrooms/1
  def destroy
    @classroom = Classroom.find(params[:id])

    authorize @classroom

    @classroom.destroy

    redirect_to classrooms_path
  end

  private

  def classroom_params
    params.require(:classroom).permit(:name, :description, avatar_attributes: [:id, :avatar, :_destroy],
      :student_ids =&gt; [])
  end

end


Here are the models:

# student.rb
class Student &lt; ActiveRecord::Base
  has_many :classroom_memberships, :dependent =&gt; :destroy, :inverse_of =&gt; :student
  has_many :classrooms, :through =&gt; :classroom_memberships
end

# classroom.rb
class Classroom &lt; ActiveRecord::Base
  has_many :classroom_memberships, :inverse_of =&gt; :classroom, :dependent =&gt; :destroy
  has_many :munchkins, :through =&gt; :classroom_memberships
end
The actions I'm wondering about are members, add_student, and remove_student. They work just fine, but they aren't RESTful [...]


True, they're not part the usual CRUD actions that can be expressed with HTTP verbs. But then neither are the default new or edit actions, so it's not like going beyond CRUD is automatically illegal.

Even so, associations do always present a bit of challenge. Are you adding the student to the class, or the class to the student?

However, in this case it appears that you already have a join model: ClassroomMembership. So going back to the CRUD actions, consider what you're creating when you call add_student: A membership.

So what you might want to do is simply make a ClassroomMembershipsController, since that's the resource you're manipulating. Said controller can then have the usual RESTful CRUD actions, keeping StudentsController or ClassroomController pretty clean.

This is just an idea, though. Again, if it's simpler to keep your actions on the ClassroomController then do that. But conceptually what you're doing is manipulating the association model.