RailsNewbie
RailsNewbie

Reputation: 155

"One-to-Many" Rails Form Creation

I have an association of One Classroom has Many Students. I want to create a form where I can create a student and assign him a classroom. And I am having problems creating the form.

model/classroom.rb

class Classroom < ActiveRecord::Base
  has_many :students
end

model/student.rb

class Student < ActiveRecord::Base
  belongs_to :classroom
end

I want to create a new student and assign it to a certain classroom.

<%= form_for(@student) do |f|%>


<%= f.label :name %>
<%= f.text_field :name %>

<br />
<br />

<%= f.label :student.classroom.number %>       #Is this correct? 
<%= f.text_field :student.classroom.number %>  #Is this correct?

<%= f.submit %>

<%end%>

The attributes for each model are

1.9.3-p448 :026 > Classroom
 => Classroom(id: integer, number: string, created_at: datetime, updated_at: datetime) 
1.9.3-p448 :027 > Student
 => Student(id: integer, name: string, created_at: datetime, updated_at: datetime, classroom_id: string) 

students_controller

class StudentsController < ApplicationController
  def index
    @students = Student.all
  end

  def show
    @student = Student.find(params[:id])
  end

  def new
    @student = Student.new
  end

  def create
    @student = Student.new(article_params)
    respond_to do |format|
    if @student.save
      format.html {redirect_to(@student, notice: 'Student was successfully created.')}
    else
      format.html {render action: "new"}
    end
end
  end

  private
    def article_params
      params.require(:student).permit(:name, :classroom_id)
    end
  end

classroom_controller

class ClassroomsController < ApplicationController
  def index
    @classrooms = Classroom.all
  end

  def show
    @classroom = Classroom.find(params[:id])
  end

  def new
    @classroom = Classroom.new
  end

  def create
    @classroom = Classroom.new(article_params)
    respond_to do |format|
    if @classroom.save
      format.html {redirect_to(@classroom, notice: 'Classroom was successfully created.')}
    else
      format.html {render action: "new"}
    end  
end
  end

  private
    def article_params
      params.require(:classroom).permit(:number)
    end
  end

Upvotes: 0

Views: 68

Answers (2)

Jesse Mignac
Jesse Mignac

Reputation: 305

You can set a hidden field setting it to the classroom itself, if you already know which classroom you want to add him in:

<%= f.hidden_field, :classroom_id, value: here_you_put_the_classroom_id $>

And don't forget to add :classroom_id in the permitted params in your controller.

Another way you can do if you want the option to select the classroom you are putting the student in, you can create a select field passing all the classrooms.

<% classroom_array = Classroom.all.map { |classroom| [classroom.name, classroom.id] } %>
<%= options_for_select(classroom_array) %>

Don't forget to add the permitted params again. Hope it helps.

***UPDATE***

The options_for_select should go inside de select tag, like this:

<% classroom_array = Classroom.all.map { |classroom| [classroom.number, classroom.id] } %> 
<%= f.label :classroom %> 
<%= f.select(:classroom_id, options_for_select(classroom_array)) %>

***UPDATE 2***

Pluck could also be an option, as long as you pass the classroom id as param. So, the code can be refactored to:

<%= f.label :classroom %>
<%= f.select :classroom_id, Classroom.all.pluck(:name, :id) %>

Upvotes: 1

bdx
bdx

Reputation: 3516

Assuming you want to assign the Student to an existing Classroom:

First, ensure the Student model has the following in the attr_accessible:

attr_accessible :classroom_id

In your form, instead of your second label/text_field, you should then be able to do:

<%= f.label :classroom %>
<%= f.select(:classroom_id, Classroom.all.pluck(:number)) %>

Note that for the f.select method you must pass the attribute you are setting, not the association name (i.e., classroom_id not classroom)

Also note that best practice would be to move logic associated with collecting information from a model (i.e. Classroom.all.pluck(:number)) into an instance variable in the controller,

e.g. @classrooms = Classroom.all.pluck(:number)

and using that @classrooms instance variable in your view instead.

Aside from the above, you should also read some more about symbols. What you've tried there with :student.classroom.number isn't going to work how you thought it might. There's a good SO question about it here: When to use symbols instead of strings in Ruby?

Upvotes: 1

Related Questions