Reputation: 379
Gurus,
I am making a simple edit form and am getting this error in Rails 4.x. The interesting thing is that the edit.html.erb is basically a copy of new.html.erb for the most part and the new.html.erb is working just fine.
The error is:
param is missing or the value is empty: teacher
def teacher_params
params.require(:teacher).permit(:firstname,
:lastname,
:email,
:cellphone,
The application trace is:
app/controllers/teacher_controller.rb:39:in `teacher_params'
app/controllers/teacher_controller.rb:23:in `edit'
The edit form is:
<h1>Add A teacher</h1>
<%= form_for @teacher, :url => { :action => 'edit'}, :id => @teacher.id, :html => { :multipart => true } do |f| %>
<table summary="teacher form fields">
<tr>
<th>First Name*</th>
<td><%= f.text_field :firstname %></td>
</tr>
<tr>
<th>Last Name*</th>
<td><%= f.text_field :lastname %></td>
</tr>
<tr>
<th>Email*</th>
<td><%= f.email_field :email %></td>
</tr>
<tr>
<th>Cellphone</th>
<td><%= f.telephone_field :cellphone %></td>
</tr>
<tr>
<th>Username*</th>
<td><%= f.text_field :username %></td>
</tr>
<tr>
<tr>
<th>Password*</th>
<td><%= f.password_field :password %></td>
</tr>
<tr>
<th>Confirm Password*</th>
<td><%= f.password_field :password_confirmation %></td>
</tr>
<tr>
<th>Address Street#</th>
<td><%= f.text_field :addr_streetno %></td>
<th>Apt #</th>
<td><%= f.number_field :addr_aptno %></td>
</tr>
<tr>
<th>City</th>
<td><%= f.text_field :addr_city %></td>
<th>State</th>
<td><%= f.text_field :addr_state %></td>
<th>Zip</th>
<td><%= f.number_field :addr_zip %></td>
</tr>
<tr>
<th>Photo</th>
<td><%= f.file_field :photo %></td>
</tr>
</table>
<%= f.submit 'Update teacher' %>
<% end %>
<% if @teacher.errors.any? %>
<ul class="Signup_Errors">
<% for message_error in @teacher.errors.full_messages %>
<li>* <%= message_error %></li>
<% end %>
</ul>
<% end %>
</div>
The model is:
class Teacher < ActiveRecord::Base
has_many :students
has_secure_password
EMAIL_REGEX = /\A[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}\z/i
CELLPHONE_REGEX = /\A([0-9]( |-)?)?(\(?[0-9]{3}\)?|[0-9]{3})( |-)?([0-9]{3}( |-)?[0-9]{4}|[a-zA-Z0-9]{7})\z/i
validates :firstname, :presence => true
validates :lastname, :presence => true
validates :username, :presence => true, :uniqueness => true, :length => { :in => 3..20 }
validates :email, :presence => true, :uniqueness => true, :format => EMAIL_REGEX
validates :cellphone, :presence => true, :format => CELLPHONE_REGEX
validates :addr_aptno, numericality: { only_integer: true, :greater_than => 0 }
validates :addr_zip, numericality: { only_integer: true, :greater_than => 0 }
end
Here is the teacher controller:
class TeacherController < ApplicationController def index @teachers= Teacher.all end
def new
@teacher = Teacher.new
end
def create
@teacher = Teacher.new(teacher_params)
if @teacher.save
flash[:notice] = "Teacher created."
redirect_to :action => 'index'
else
render :action => 'new'
end
end
def edit
@teacher = Teacher.find(params[:id])
# Update the object
if @teacher.update_attributes(teacher_params)
# If update succeeds, redirect to the list action
flash[:notice] = "Teacher updated."
redirect_to :action => 'index'
else
# If save fails, redisplay the form so user can fix problems
render :action => 'edit'
end
end
def show
end
private
def teacher_params
params.require(:teacher).permit(:firstname,
:lastname,
:email,
:cellphone,
:username,
:password,
:password_confirmation,
:addr_streetno,
:addr_aptno,
:addr_city,
:addr_state,
:addr_zip,
:photo)
end
end
Here is the migration file:
create_table :teachers do |t|
t.string :firstname, null: false
t.string :lastname, null: false
t.string :email, null: false
t.string :cellphone
t.string :username, null: false
t.string :password_digest, null: false
t.string :addr_streetno
t.integer :addr_aptno
t.string :addr_city
t.string :addr_state
t.integer :addr_zip
t.binary :photo, :limit => 0.5.megabyte
t.timestamps
end
Upvotes: 2
Views: 6884
Reputation: 379
Essentially, I had to split the edit action in the controller into udpate and edit. I saw a working example on lynda.com and followed it. Also other people said the same thing. Now its working.
I had to add the :patch keywords in routes.rb
match ':controller(/:action/(:id))', :via => [:get, :post, :patch]
The edit form was a replica of the new form except that the action was update instead of create and that the id had to be passed.
<%= form_for @teacher, :url => { :action => 'update', :id => @teacher.id}, :html => { :multipart => true } do |f| %>
This was the new code in the controller:
def edit
@teacher = Teacher.find(params[:id])
end
def update
@teacher = Teacher.find(params[:id])
# Update the object
if @teacher.update_attributes(teacher_params)
# If update succeeds, redirect to the list action
flash[:notice] = "Teacher updated."
redirect_to :action => 'show', :id => @teacher.id
else
# If update fails, redisplay the form so user can fix problems
render :action => 'edit'
end
end
Upvotes: 0
Reputation: 2662
You have to split the edit action into 2 actions since edit is default just a get
request:
def edit
@teacher = Teacher.find(params[:id])
respond_to { |format| format.html }
end
def update
@teacher = Teacher.find(params[:id])
if @teacher.update_attributes(teacher_params)
...
end
Also remove :url => { :action => 'edit'}
from your form, since it's routing to the update
action. This happens automatically if you use <%= form_for @teacher do |f|%>
Upvotes: 2