new.html is a registration form ,which creates tutor account .
It involves error handling . _error_messages.html.erb is the file which handles the error ,like should be filling in all text fields .
e.g , showing :
`
The form contains 3 errors.
Name can't be blank
Password confirmation can't be blank
Password confirmation doesn't match Password
However ,when submits the form without any input in new.html ,it shows the error
Missing template tutors/register, application/register with {:locale=>[:en], :formats=>[:html], :variants=>[], :handlers=>[:erb, :builder, :raw, :ruby, :coffee, :jbuilder]}. Searched in: * "C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/web-console-2.0.0/lib/action_dispatch/templates" * "D:/Sites/abc/app/views"
new.html.erb
<% provide(:title, 'Registeration') %>
<h1>Tutor Registration</h1>
<div class="row">
<div class="col-md-6 col-md-offset-3">
<%= form_for(#tutor) do |f| %>
<%= render 'shared/error_messages' %>
<%= f.label :name %>
<%= f.text_field :name, class: 'form-control' %>
<%= f.label :email %>
<%= f.text_field :email, class: 'form-control' %>
<%= f.label :password %>
<%= f.password_field :password, class: 'form-control' %>
<%= f.label :password_confirmation, "Confirm Password" %>
<%= f.password_field :password_confirmation, class: 'form-control' %>
<%= f.label :gender %>
<%= f.select(:gender, ['Male', 'Female'] , class: 'form-control' )%>
<%= f.label :tutor_education_level %>
<%= f.select(:education_level, ['Bachelor', 'Master', 'Doctor'] , class: 'form-control' )%>
<%= f.label :tutor_institution %>
<%= f.text_field :institution, class: 'form-control' %>
<%= f.label :tutorial_experience %>
<%= f.text_field :experience, class: 'form-control' %>
<%= f.label :tutor_preferred_district %>
<%= f.text_field :district, class: 'form-control' %>
<%= f.label :tutor_preferred_subject %>
<%= f.text_field :subject, class: 'form-control' %>
<%= f.label :tutor_required_student_level %>
<%= f.select(:student_level, ['P1-P3', 'P4-P6', 'S1-S3', 'S4-S6'] , class: 'form-control' )%>
<%= f.submit "Create tutor's account", class: "btn btn-primary" %>
<% end %>
</div>
</div>
views/shared/_error_messages.html.erb
<% if #tutor.errors.any? %>
<div id="error_explanation">
<div class="alert alert-danger">
The form contains <%= pluralize(#tutor.errors.count, "error") %>.
</div>
<ul>
<% #tutor.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
Tutor -controller
class TutorsController < ApplicationController
before_action :logged_in_tutor, only: [:edit, :update]
before_action :correct_tutor, only: [:edit, :update]
def index
#tutors = Tutor.all
end
def show
#tutor = Tutor.find(params[:id])
end
def new
#tutor = Tutor.new
end
def create
#tutor = Tutor.new(tutor_params)
if #tutor.save
log_in #tutor
flash[:success] = "Congratulations! Your registration is successful!"
redirect_to #tutor
else
render 'register'
end
end
def edit
#tutor = Tutor.find(params[:id])
end
def update
if #tutor.update_attributes(tutor_params)
flash[:success] = "Profile updated successfuly!"
redirect_to #tutor
else
render 'edit'
end
end
# Handle sign-up failure, to redirect the tutor to the registeration form again
def tutor_params
params.require(:tutor).permit(:name, :email, :password, :password_confirmation, :address,:gender ,:education_level,:institution,:exprience,:district,:subject,:student_level)
end
def logged_in_tutor
unless logged_in?
store_location
flash[:danger] = "Please log in."
redirect_to login_url
end
end
def correct_tutor
#tutor = Tutor.find(params[:id])
redirect_to(root_url) unless current_tutor?(#tutor)
end
end
When you submit the form, request sends to the create action:
def create
#tutor = Tutor.new(tutor_params)
if #tutor.save
# if #tutor valid save it and redirect to show action
redirect_to #tutor
else
# else render the register template(or action)
render 'register'
end
end
In the create action there is a conditional if, in the first case all is good, #tutor has been saved and Rails call redirect to show action, otherwise Rails trying to render register template which is not exists(the errors claims about it). To resolve that issue create register template with desired html code which should run if #tutor isn't saved.
Related
So I have two models, User and Employee. User has one employee and Employee belongs to User. I want to create an employee but first I have to create a new User. My Employee model does not have the attributes :email, :password, :password_confirmation so I created virtual attributes. This is the error that pops up Validation failed: Email is invalid, Password confirmation doesn't match Password
here is my employee model
class Employee < ApplicationRecord
belongs_to :user
attr_accessor :email, :password, :password_confirmation
validates :email, format: { with: /\A([^#\s]+)#((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i, on: :create }
validates :password, confirmation: true
end
my employee controller
class EmployeesController < ApplicationController
def create
#newuser=User.create!(
email: :email,
password: :password,
password_confirmation: :password_confirmation
)
#employee = Employee.new(employee_params)
respond_to do |format|
if #employee.save
format.html { redirect_to #employee, notice: 'Employee was successfully created.' }
format.json { render :show, status: :created, location: #employee }
else
format.html { render :new }
format.json { render json: #employee.errors, status: :unprocessable_entity }
end
end
end
private
def employee_params
params.require(:employee).permit(:name, :contact_no, :role_id, #newuser.id)
end
end
And my form
<%= form_for(employee) do |f| %>
<% if employee.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(employee.errors.count, "error") %> prohibited this employee from being saved:</h2>
<ul>
<% employee.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :email %>
<%= f.email_field :email %>
</div>
<div class="field">
<%= f.password_field :password %>
<%= f.password_field :password_confirmation %>
</div>
<div class="field">
<%= f.label :name %>
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :contact_no %>
<%= f.text_field :contact_no %>
</div>
<div class="field">
<%= f.label :role_id %>
<%= f.number_field :role_id %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
I'm still learning rails and would greatly appreciate your help
if you don't have attributes :email, :password, :password_confirmation then remove the following validation:
validates :email, format: { with: /\A([^#\s]+)#((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i, on: :create }
validates :password, confirmation: true
from Employee Model.
I have found the solution to my problem, it seems that my user parameters weren't following rails' strong parameters rule. so my controller has this now
def employee_params
params.require(:employee).permit(:name, :contact_no, :role_id)
end
def user_params
params.require(:employee).permit(:email, :password, :password_confirmation)
end
I was then able to make the user using the parameters without a problem.
So i am getting trouble in saving form data,.Any help will b appreciable
form is submitted without getting any error, but in database, nothing is stored
i am new on rails
users_controller
class UsersController < ApplicationController
def new
#user= User.new
end
def create
#user = User.new(params[:User])
if #user.save
flash[:notice]= "you signed up successfully"
flash[:color]= "valid"
else
flash[:notice]= "failed"
flash[:color]="invalid"
end
render "new"
end
end
new.html.erb
<% page_title="Signup" %>
<div class="Sign_Form">
<h1>Sign up</h1>
<%= form_for(:user, :url => {:controller => 'users', :action => 'create'}) do |f| %>
<p> Username:</br> <%= f.text_field :username %> </p>
<p> Email:</br> <%= f.text_field :email %> </p>
<p> Password:</br> <%= f.password_field :password %></p>
<p> Password Confirmation:</br> <%= f.password_field :password_confirmation %> </p>
<%= f.submit :Signup %>
<% end %>
<% if #user.errors.any? %>
<ul class="Signup_Errors">
<% for message_error in #user.errors.full_messages %>
<li>* <%= message_error %></li>
<% end %>
</ul>
<% end %>
</div>
in app/models/user.rb
class User < ActiveRecord::Base
attr_accessor :password
EMAIL_REGEX = /^[A-Z0-9._%+-]+#[A-Z0-9.-]+\.[A-Z]{2,4}$/i
validates :username, :presence => true, :uniqueness => true, :length => { :in => 3..20 }
validates :email, :presence => true, :uniqueness => true #:format => EMAIL_REGEX
validates :password, :presence =>true #:confirmation => true #password_confirmation attr
validates_length_of :password, :in => 6..20, :on => :create
end
In users_controller, create method, you are using
#user = User.new(params[:User])
replace it with following code, hope it will work fine.
#user = User.new(params[:user])
And,also use strong params if you are using rails 4. Like follwoing.
def create
#user = User.new(user_params)
if #user.save
flash[:notice]= "you signed up successfully"
flash[:color]= "valid"
else
flash[:notice]= "failed"
flash[:color]="invalid"
end
render "new"
end
private
def user_params
params.require(:user).permit(:username, :account, :email, :password, :password_confirmation)
end
If, it still not works, then, please display your log.
If you are using Rails 4 you need to use strong parameters to whitelist the parameters you want to assign to your models.
This became non-optional in Rails 4 to prevent mass-assignment vulnerabilities where a malicious user can assign any property to a model after Egor Homakovs much publicised Github attack.
Also note that Ruby is case sensitive. This applies to hash keys as well:
irb(main):003:0> hash = { a: 1 }
=> {:a=>1}
irb(main):004:0> hash[:A]
=> nil
Which is why why you do User.new(params[:User]) you are actually doing User.new(nil)
This is a corrected version of your controller
class UsersController < ApplicationController
def new
#user= User.new
end
def create
#user = User.new(params[:User])
if #user.save
flash[:notice]= "you signed up successfully"
flash[:color]= "valid"
# You should redirect instead of rendering the form again
redirect_to #user # or redirect_to root_path
else
flash[:notice]= "failed"
flash[:color]="invalid"
render "new" # Needs to be inside the "else" statement
# Otherwise you will get a double render error
end
end
def user_params
params.require(:user)
.allow(:username, :email, :password, :password_confirmation)
end
end
Added:
You can also simplify your form_for to
<%= form_for(:user) do |f| %>
Rails will by convention route the form to UserController#create.
Also you should use <label> tags for accessibility, as they help people who use assistive technology such as screen readers to find the correct inputs.
By using the built in label helper rails will set up the for attribute and you can translate the label texts with Rails built in I18n functionality.
<% page_title="Signup" %>
<div class="Sign_Form">
<h1>Sign up</h1>
<%= form_for(:user) do |f| %>
<div class="row">
<%= f.label :username %>:</br>
<%= f.text_field :username %>
</div>
<div class="row">
<%= f.label :email %>:</br>
<%= f.text_field :email %>
</div>
<div class="row">
<%= f.label :password %>:</br>
<%= f.password_field :password %>
</div>
<%= f.submit :Signup %>
<% end %>
<% if #user.errors.any? %>
<ul class="Signup_Errors">
<%# for loops are almost never used in ruby. %>
<%# .each is the idiomatically correct way %>
<% #user.errors.full_messages.each do |message_error| %>
<li>* <%= message_error %></li>
<% end %>
</ul>
<% end %>
</div>
I am doing a basic validation for a bank entry and am trying to display the errors on submit. Here is my validation and html.
controller:
class PagesController < ApplicationController
def index
#guestbook_entries = GuestbookEntry.all
#guestbook_entry = GuestbookEntry.new
render "welcome"
end
end
class GuestbookEntry < ActiveRecord::Base
validates :body, presence: :true
end
This is my html:
<% form_for #guestbook_entry do |f| %>
<% if f.errors.any? %>
<% f.errors.full_messages.each do |m| %>
<li><%= m %></li>
<% end %>
<% end %>
<%= f.label :body, "Guestbook Entry:" %>
<%= f.text_area :body %>
<%= f.submit "Submit" %>
<% end %>
Any ideas?
I am new to ruby. I have the same form but i need it to perform creation/updation as and when required. The problem i have now is that whenever i call edit instead of editing the details of an existing user, i am getting a new user with the edited details. To put it simply, i think whenever i perform edit, the create method is being called.
So is there any way to use single form for both new and edit instead of using separate forms.
The following code is for editing user details:
<%= link_to 'Home', root_path %>
<h2>Edit user</h2>
<%= form_for :user, url: user_index_path do |f| %>
<p>
<%= f.label :name %><br>
<%= f.text_field :name %>
</p>
<p>
<%= f.label :address %><br>
<%= f.text_area :address %>
</p>
<p>
<%= f.label :email %><br>
<%= f.text_field :email %>
</p>
<p>
<%= f.label :phone %><br>
<%= f.text_field :phone %>
</p>
<p>
<%= f.label :state %><br>
<%= f.text_field :state %>
</p>
<p>
<%= f.label :country %>
<%= f.collection_select(:country, Country.all, :name, :name) %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
The following code is for creating user:
<%= link_to 'Home', root_path %>
<h2>Create new user</h2>
<%= form_for :user, url: user_index_path do |f| %>
<p>
<%= f.label :name %><br>
<%= f.text_field :name %>
</p>
<p>
<%= f.label :address %><br>
<%= f.text_area :address %>
</p>
<p>
<%= f.label :email %><br>
<%= f.text_field :email %>
</p>
<p>
<%= f.label :phone %><br>
<%= f.text_field :phone %>
</p>
<p>
<%= f.label :state %><br>
<%= f.text_field :state %>
</p>
<p>
<%= f.label :country %>
<%= f.collection_select(:country, Country.all, :name, :name) %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
And this is my controller:
class UserController < ApplicationController
def index
#users = User.all
end
def show
#user = User.find(params[:id])
end
def new
#user = User.new
end
def create
#user = User.new(user_params)
if #user.save
redirect_to #user
else
render 'new'
end
end
def edit
#user = User.find(params[:id])
end
def update
##user = User.find(params[:id])
if #user.update(user_params)
redirect_to #user
else
render 'edit'
end
end
def destroy
#user = User.find(params[:id])
#user.destroy
redirect_to user_index_path
end
private
def user_params
params.require(:user).permit(:name, :address, :email, :phone, :state, :country)
end
end
Since i am new to ruby, i did not get the exact details of how http requests function in ruby.
users/_form.html.erb
<%= link_to 'Home', root_path %>
<%= form_for #user do |f| %>
<p>
<%= f.label :name %><br>
<%= f.text_field :name %>
</p>
<p>
<%= f.label :address %><br>
<%= f.text_area :address %>
</p>
<p>
<%= f.label :email %><br>
<%= f.text_field :email %>
</p>
<p>
<%= f.label :phone %><br>
<%= f.text_field :phone %>
</p>
<p>
<%= f.label :state %><br>
<%= f.text_field :state %>
</p>
<p>
<%= f.label :country %>
<%= f.collection_select(:country, Country.all, :name, :name) %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
users/new.html.erb
<h2>Create new user</h2>
<%= render 'form' %>
users/edit.html.erb
<h2>Edit user</h2>
<%= render 'form' %>
users_controller.rb
class UsersController < ApplicationController
before_filter :find_user, only: [:show, :edit, :update, :destroy]
def index
#users = User.all
end
def show
end
def new
#user = User.new
end
def create
#user = User.new(user_params)
if #user.save
redirect_to #user
else
render 'new'
end
end
def edit
end
def update
if #user.update(user_params)
redirect_to #user
else
render 'edit'
end
end
def destroy
#user.destroy
redirect_to user_index_path
end
private
def user_params
params.require(:user).permit(:name, :address, :email, :phone, :state, :country)
end
def find_user
#user = User.find(params[:id])
end
end
When you have same view code for two or more methods, you should create a partial of same view code and render it in those methods. This is called DRY principle in ruby on rails
I have a nested form.
Right now I want to arrange the layout with some CSS but I am facing trouble allocating dom ids to the form.
This is the subject controller.
I want to allocate lesson_type as seen in line 5 as the dom id.
1 def index
2 #subjects = Subject.all
3 #subject = Subject.new
4 lecture = #subject.lessons.build
5 lecture.lesson_type = "lecture"
lecture.lesson_groups.build
lecture.destroy
tutorial = #subject.lessons.build
tutorial.lesson_type = "tutorial"
tutorial.lesson_groups.build
tutorial.destroy
laboratory = #subject.lessons.build
laboratory.lesson_type = "laboratory"
laboratory.lesson_groups.build
laboratory.destroy
respond_to do |format|
format.html # index.html.erb
format.json { render json: #subjects }
format.js
end
end
The following is the form.
<%= nested_form_for(#subject, :remote=>true) do |f| %>
<% if #subject.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#subject.errors.count, "error") %> prohibited this subject from being saved:</h2>
<ul>
<% #subject.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :subject_code %><br />
<%= f.text_field :subject_code %>
</div>
<%= f.fields_for :lessons do |lesson| %>
<%= lesson.label :lesson_type %><br/>
<%= lesson.text_field :lesson_type, :readonly=>true%><br/>
<%= lesson.label :name %><br/>
<%= lesson.text_field :name %><br/>
<%= lesson.fields_for :lesson_groups do |lesson_group| %>
<%= lesson_group.label :group_index %><br/>
<%= lesson_group.text_field :group_index %>
<%= lesson_group.link_to_remove "Remove this task" %>
<% end %>
This is the div where I want to add an id to.
<%= f.fields_for :lessons do |lesson| %>
<%= lesson.label :lesson_type %><br/>
<%= lesson.text_field :lesson_type, :readonly=>true%><br/>
<%= lesson.label :name %><br/>
<%= lesson.text_field :name %><br/>
I have tried out the following but it did not worked.
<div id = "<%= :lesson_type%>">
Would appreciate it if someone could help me out thanks.
sorry..
#controller
def index
...
lecture.lesson_type = #lesson_dom_id = "lecture" # line 5
...
end
#view
<div id="<%= #lesson_dom_id %>">