api. Now need to insert a record which has associated records. I read nested attributes but didn't get any idea. I can't understand well.
I tried with one example in rails mvc project but even i can't create associated record in one-one mapping itself. Please guid me what the steps to do this or any good articles with sample?
Anyway the following is my workings
My model is
class Instructor < ActiveRecord::Base
has_one :office_assignment
has_many :departments
has_and_belongs_to_many :courses
accepts_nested_attributes_for :office_assignment
end
class OfficeAssignment < ActiveRecord::Base
belongs_to :instructor
end
My controller methods for create
def new
#instructor = Instructor.new
end
def create
#instructor = Instructor.new(instructor_params)
respond_to do |format|
if #instructor.save
format.html { redirect_to #instructor, notice: 'Instructor was successfully created.' }
format.json { render :show, status: :created, location: #instructor }
else
format.html { render :new }
format.json { render json: #instructor.errors, status: :unprocessable_entity }
end
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_instructor
#instructor = Instructor.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def instructor_params
params.require(:instructor).permit(:LastName, :FirstMidName, :HireDate, office_assignment_attributes: [:Location])
end
My create form
<%= form_for #instructor, :html => { :class => "form-horizontal instructor" } do |f| %>
<% if #instructor.errors.any? %>
<div id="error_expl" class="panel panel-danger">
<div class="panel-heading">
<h3 class="panel-title"><%= pluralize(#instructor.errors.count, "error") %> prohibited this instructor from being saved:</h3>
</div>
<div class="panel-body">
<ul>
<% #instructor.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
</div>
<% end %>
<div class="form-group">
<%= f.label :LastName, :class => 'control-label' %>
<div class="controls">
<%= f.text_field :LastName, :class => 'form-control' %>
</div>
<%= error_span(#instructor[:LastName]) %>
</div>
<div class="form-group">
<%= f.label :FirstMidName, :class => 'control-label' %>
<div class="controls">
<%= f.text_field :FirstMidName, :class => 'form-control' %>
</div>
<%= error_span(#instructor[:FirstMidName]) %>
</div>
<div class="form-group">
<%= f.label :HireDate, :class => 'control-label' %>
<div class="controls">
<%= f.text_field :HireDate, :class => 'form-control' %>
</div>
<%= error_span(#instructor[:HireDate]) %>
</div>
<div class="form-group">
<%= f.label :Location, :class => 'control-label' %>
<div class="controls">
<input type="text" name="office_assignment_Location" class ="form-control">
</div>
<%= error_span(#instructor[:HireDate]) %>
</div>
<%= f.submit nil, :class => 'btn btn-primary' %>
<%= link_to t('.cancel', :default => t("helpers.links.cancel")),
instructors_path, :class => 'btn btn-default' %>
<% end %>
Please guide me..
Edit:
Changes in html file
<%= f.fields_for :office_assignment_Location do |loc| %>
<div class="form-group">
<%= loc.label :Location, :class => 'control-label' %>
<div class="controls">
<%= loc.text_field :Location %>
</div>
</div>
<%= loc.link_to_add "Add Location", :office_assignment_Location , :class=>'btn btn-primary'%>
<% end %>
My param in controller
def instructor_params
params.require(:instructor).permit(:LastName, :FirstMidName, :HireDate, office_assignment_attributes: [:id, :Location ,:_destroy])
end
My schema
create_table "instructors", force: :cascade do |t|
t.string "LastName", limit: 255
t.string "FirstMidName", limit: 255
t.date "HireDate"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "office_assignments", primary_key: "Instructor_Id", force: :cascade do |t|
t.string "Location", limit: 255
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_foreign_key "office_assignments", "instructors", column: "Instructor_Id"
FYI: attribute's name should start with small letter not capital.
Here are some changes:
class Instructor < ActiveRecord::Base
has_one :office_assignment , :dependent => :destroy # add dependent destroy
has_many :departments
has_and_belongs_to_many :courses
accepts_nested_attributes_for :office_assignment, :reject_if => :all_blank, :allow_destroy => true # add allow destroy
end
Some change in strong Parameters:
def instructor_params
params.require(:instructor).permit(:LastName, :FirstMidName, :HireDate, office_assignment_attributes: [:id, :Lesson ,:_destroy])
end
Note: Don't forget to add :id and :_destroy in office_assignment_attributes
Now in View(form_template):
Instead of this:
<div class="form-group">
<%= f.label :Location, :class => 'control-label' %>
<div class="controls">
<input type="text" name="office_assignment_Location" class ="form-control">
</div>
<%= error_span(#instructor[:HireDate]) %>
</div>
It should be:
<%= nested_form_for #instructor, :html => { :class => "form-horizontal instructor" } do |f| %>
......
.....
<%= f.fields_for :office_assignment do |loc| %>
<div class="form-group">
<%= loc.label :Location, :class => 'control-label' %>
<div class="controls">
<%= loc.text_field :Location %>
</div>
</div>
<% end %>
<%= f.link_to_add "Add Location", :office_assignment , :class=>'btn btn-primary'%>
You have to create nested form like this. I hope this helps you.
Note: Use nested_form_for instead of form_for in your form:
For your reference:
http://railscasts.com/episodes/196-nested-model-form-part-1
http://railscasts.com/episodes/197-nested-model-form-part-2
Related
I am getting the below error while my page is failed to lagged in.If i am typing wrong password/email and clicked on submit then the bellow error is coming.
Error:
Template is missing
Missing template sessions/member, application/member with {:locale=>[:en], :formats=>[:html], :handlers=>[:erb, :builder, :coffee]}. Searched in: * "C:/Site/library_management1/app/views" * "C:/Ruby193/lib/ruby/gems/1.9.1/gems/devise-3.4.1/app/views"
My codes are as follows.
views/homes/member.html.erb
<% if current_user %>
<div class="totaldiv">
<div class="navdiv"><span>STUDENT INFORMATION</span><span>Logged in as <%= current_user.email %></span></div>
<div class="wrapper">
<div id="leftsidebtn">
<ul>
<li>Book issue</li>
<li>Books Available</li>
<li>Log Out</li>
</ul>
</div>
</div>
<div class="restdiv" id="ex3" >
<center>
</center>
</div>
</div>
<% else %>
<div class="totaldiv">
<div class="navdiv"><span>STUDENT INFORMATION</span></div>
<div class="wrapper">
<div id="leftsidebtn">
<ul>
<li>Registration</li>
<li>Back</li>
</ul>
</div>
</div>
<div class="restdiv" id="ex3" >
<center>
<div class="studentlogin">
<h1>Login Here</h1>
<section class="studentloginloginform cf">
<%= form_for :users,:url => {:action => 'loginuser',:controller => 'sessions'} do |f| %>
<% if #users.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#users.errors.count, "error") %> prohibited this post from being saved:</h2>
<ul>
<% #users.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<ul>
<li>
<label for="usermail">Email</label>
<%= f.email_field :email,placeholder:"yourname#email.com" %>
</li>
<li>
<label for="password">Password</label>
<%= f.password_field :password,placeholder:"password" %>
</li>
<li>
<%= f.submit 'LogIn',:class => 'studentsubmit' %>
</li>
<li class="reg_member">
Not a member ? <%= link_to 'Register Here',homes_registration_path %>
</li>
</ul>
<% end %>
</section>
</div>
</center>
</div>
</div>
<% end %>
controller/sessions_controller.rb
class SessionsController < ApplicationController
def loginuser
#users=User.authenticate(params[:users][:email], params[:users][:password])
if #users
session[:user_id]=#users.id
cookies.signed[:user_id]=#users.id
flash[:notice]="login successfull"
flash[:color]="valid"
redirect_to :action => 'member',:controller => 'homes'
else
flash[:notice]="could not Logged in"
flash[:color]="invalid"
render 'member', :controller => 'homes'
end
end
def removeuser
session[:user_id] = nil
cookies.delete :user_id
flash[:notice]="user logged out successfully"
flash[:color]="valid"
redirect_to :action => 'member', :controller => 'homes'
end
end
model/user.rb
class User < ActiveRecord::Base
attr_accessible :address, :email, :first_name, :last_name, :password, :password_hash, :password_salt, :tel_no ,:password_confirmation
attr_accessor :password
before_save :encrypt_password
EMAIL_REGEX = /\A[A-Z0-9._%+-]+#[A-Z0-9.-]+\.[A-Z]{2,4}\z/i
validates :email, :presence => true, :uniqueness => true, :format => EMAIL_REGEX
validates :first_name, :presence => true, :length => {:in => 3..10}
validates :last_name , :presence => true , :length => {:in => 3..10}
validates :tel_no , :presence => true , :length => {:in => 1..10}
validates :password, :confirmation => true
validates_length_of :password, :in => 6..20, :on => :create
def self.authenticate(email, password)
user = find_by_email(email)
if user && user.password_hash == BCrypt::Engine.hash_secret(password, user.password_salt)
user
else
nil
end
end
def encrypt_password
if password.present?
self.password_salt = BCrypt::Engine.generate_salt
self.password_hash = BCrypt::Engine.hash_secret(password, password_salt)
end
end
has_many :issue
has_many :book
end
Please check the codes and try to resolve this error.
In your controller change line render 'member', :controller => 'homes' with following.
render 'homes/member'
You template is missing on "sessions/member" path
I guess, create a template in following path to resolve it
views/sessions/member.html.erb
I got a task to integrate multiple models in a single form.I have one form 'register' and two models buyer and address. But by doing this i can not attach two forms together.
_form.html.erb is
<% #register.buyers.build %>
<%= form_for(#register) do |f| %>
<% if #register.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#register.errors.count, "error") %> prohibited this register from being saved:</h2>
<ul>
<% #register.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :date %><br />
<%= f.date_select :date %>
</div>
<div class="field">
<h4>Buyer</h4>
</div>
<div class="field">
<%# f.fields_for :buyers do |builder| %>
<%= render :partial => "buyer_fields", :locals => {:f => f } %>
<%# end %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
_buyer_fields.html.erb is
<% f.fields_for :buyers do |buyers_form| %>
<div class="fields">
<p>
<%= buyers_form.label :name, "Name" %><br/>
<%= buyers_form.text_field :name %>
</p>
<h4>Address</h4>
<% f.fields_for :addresses do |builder| %>
<%= render :partial => 'address_fields', :locals => { :f => builder} %>
<% end %>
</div>
<% end%>
and the _address_fields.html.erb is
<p class="fields">
<table>
<tr>
<td>
<%= f.text_area :name, :rows => "2",:cols => "20" %>
</td>
</tr>
</table>
</p>
register model is
class Register < ActiveRecord::Base
attr_accessible :date, :book_ids,:buyers_attributes
has_many :authorships
has_many :books, :through => :authorships
has_many :buyers
#accepts_nested_attributes_for :buyers, :reject_if => lambda { |a| a[:name].blank? }, :allow_destroy => true
accepts_nested_attributes_for :buyers, :allow_destroy => :true,
:reject_if => proc { |attrs| attrs.all? { |k, v| v.blank? } }
end
buyer model is
class Buyer < ActiveRecord::Base
belongs_to :register
attr_accessible :addresses_attributes, :name
has_many :addresses, :dependent => :destroy
accepts_nested_attributes_for :addresses, :reject_if => lambda { |a| a[:name].blank? }, :allow_destroy => true
end
and address model is
attr_accessible :name
belongs_to :buyer
But only register form is displayed. How can i integrate two models in single form in ruby on rails 3.2.9? Please help.
Your nested address view is wrong.
Make some changes in buyer_fields.html.erb
<%= f.fields_for :buyers do |buyers_form| %>
<div class="fields">
<p>
<%= buyers_form.label :name, "Name" %><br/>
<%= buyers_form.text_field :name %>
</p>
<h4>Address</h4>
<%= buyers_form.fields_for :addresses do |builder| %>
<%= render :partial => 'address_fields', :locals => { :f => builder} %>
<% end %>
</div>
<% end %>
I have some nested models in my Rails application.
i have an article hat has mny properties.
class Article < ActiveRecord::Base
has_many :properties, :dependent => :destroy
accepts_nested_attributes_for :properties
end
class Property < ActiveRecord::Base
belongs_to :article
end
And now i want to edit this in my View so I editet the controler
# GET /articles/new
# GET /articles/new.json
def new
#article = Article.new
3.times { #article.properties.build }
respond_to do |format|
format.html # new.html.erb
format.json { render json: #article }
end
end
And also edited the View and the _format.html.erb
<%= form_for(#article) do |f| %>
<% if #article.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#article.errors.count, "error") %> prohibited this article from being saved:</h2>
<ul>
<% #article.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :name %><br />
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :description %><br />
<%= f.text_area :description %>
</div>
<% f.fields_for :properties do |prop| %>
<div class="field">
<%= prop.label :name %><br />
<%= prop.text_field :name %>
</div>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
But there is no way to show up. If i want to create a new Model, i can not see any input fields for the properties.
What have i do wrong?
You're missing an = in your fields_for line. That is, it should be:
<%= f.fields_for :properties do |prop| %>
I have models User, Teacher, TeacherEducation. TeacherEducation belongs to Teacher, Teacher belongs to User.
I use nested attributes to save everything via one line in my controller user.save. But I met thing which I can't solve. I can set id for Teacher, but I can't give id for TeacherEducation before I can save Teacher.
Is it possible to fix that and keep using nested attributes in my models?
class User < ActiveRecord::Base
attr_accessor :password
attr_accessible :user_login,
:password,
:teacher_attributes
has_one :teacher
accepts_nested_attributes_for :teacher
end
class Teacher < ActiveRecord::Base
attr_accessible :teacher_last_name,
:teacher_first_name,
:teacher_middle_name,
:teacher_birthday,
:teacher_sex,
:teacher_category,
:teacher_education_attributes
belongs_to :user
has_one :teacher_education
accepts_nested_attributes_for :teacher_education
validates :user_id,
:presence => true
end
class TeacherEducation < ActiveRecord::Base
attr_accessible :teacher_education_university,
:teacher_education_year,
:teacher_education_graduation,
:teacher_education_speciality
belongs_to :teacher
validates :teacher_id,
:presence => true
...
end
My controller
class AdminsController < ApplicationController
def create_teacher
user = User.new( params[:user] )
user.user_role = "teacher"
user.teacher.user_id = current_user.id # Work
user.teacher.teacher_education.teacher_id = user.teacher.id # Doesn't work
if user.save
...
end
end
end
So, user.teacher.teacher_education.teacher_id = user.teacher.id doesn't work.
UPD
Error
Teacher teacher education teacher can't be blank, Teacher user can't be blank
View - new_teacher.html.erb
<%= form_for #user, :url => create_teacher_url, :html => {:class => "form-horizontal"} do |f| %>
<%= field_set_tag do %>
<%= f.fields_for :teacher do |builder| %>
<div class="control-group">
<%= builder.label :teacher_last_name, "Фамилия", :class => "control-label" %>
<div class="controls">
<%= builder.text_field :teacher_last_name, :value => #teacher_last_name %>
</div>
</div>
<div class="control-group">
<%= builder.label :teacher_first_name, "Имя", :class => "control-label" %>
<div class="controls">
<%= builder.text_field :teacher_first_name, :value => #teacher_first_name %>
</div>
</div>
<div class="control-group">
<%= builder.label :teacher_middle_name, "Отчество", :class => "control-label" %>
<div class="controls">
<%= builder.text_field :teacher_middle_name, :value => #teacher_middle_name %>
</div>
</div>
<div class="control-group">
<%= builder.label :teacher_sex, "Пол", :class => "control-label" %>
<div class="controls">
<%= label_tag nil, nil, :class => "radio" do %>
<%= builder.radio_button :teacher_sex, 'm', :checked => #user_sex_man %>
Мужской
<% end %>
<%= label_tag nil, nil, :class => "radio" do %>
<%= builder.radio_button :teacher_sex, 'w', :checked => #user_sex_woman %>
Женский
<% end %>
</div>
</div>
<div class="control-group">
<%= builder.label :teacher_birthday, "Дата рождения", :class => "control-label" %>
<div class="controls">
<%= builder.text_field :teacher_birthday, :value => #teacher_birthday %>
<p class="help-block">Формат даты: дд.мм.гггг</p>
</div>
</div>
<div class="control-group">
<%= builder.label :teacher_category, "Категория", :class => "control-label" %>
<div class="controls">
<%= builder.text_field :teacher_category, :value => #teacher_category %>
</div>
</div>
<%= builder.fields_for :teacher_education do |edu_fields| %>
<div class="control-group">
<%= edu_fields.label :teacher_education_university, "Название ВУЗа", :class => "control-label" %>
<div class="controls">
<%= edu_fields.text_field :teacher_education_university, :value => #teacher_university %>
</div>
</div>
<div class="control-group">
<%= edu_fields.label :teacher_education_year, "Дата выпуска из ВУЗа", :class => "control-label" %>
<div class="controls">
<%= edu_fields.text_field :teacher_education_year, :value => #teacher_finish_univ %>
<p class="help-block">Формат даты: дд.мм.гггг</p>
</div>
</div>
<div class="control-group">
<%= edu_fields.label :teacher_education_graduation, "Степень", :class => "control-label" %>
<div class="controls">
<%= edu_fields.text_field :teacher_education_graduation, :value => #teacher_graduation %>
</div>
</div>
<div class="control-group">
<%= edu_fields.label :teacher_education_speciality, "Специальность", :class => "control-label" %>
<div class="controls">
<%= edu_fields.text_field :teacher_education_speciality, :value => #teacher_specl %>
</div>
</div>
<% end %>
<% end %>
<hr/>
<div class="control-group">
<%= f.label :user_login, "Логин учетной записи", :class => "control-label" %>
<div class="controls">
<%= f.text_field :user_login, :value => #user_login %>
<%= link_to_function "Сгенерировать логин", "generate_login()", :class => "btn" %>
</div>
</div>
<div class="control-group">
<%= f.label :password, "Пароль учетной записи", :class => "control-label" %>
<div class="controls">
<%= f.text_field :password, :value => #user_password %>
<%= link_to_function "Сгенерировать пароль", "generate_password()", :class => "btn" %>
</div>
</div>
<% end %>
<%= f.submit "Создать", :class => "btn btn-large btn-success" %>
<% end %>
Also, some debug information:
user: !ruby/hash:ActiveSupport::HashWithIndifferentAccess
password: somepass
teacher_attributes: !ruby/hash:ActiveSupport::HashWithIndifferentAccess
teacher_birthday: 21.12.1990
teacher_category: categ
teacher_education_attributes: !ruby/hash:ActiveSupport::HashWithIndifferentAccess
teacher_education_graduation: grad
teacher_education_speciality: spec
teacher_education_university: univ
teacher_education_year: 28.09.2000
teacher_first_name: name
teacher_last_name: last
teacher_middle_name: middle
teacher_sex: w
user_login: schoolh_Lyp1v
utf8: ✓
controller: admins
My schema
create_table "teacher_educations", :force => true do |t|
t.integer "teacher_id"
t.string "teacher_education_university"
t.date "teacher_education_year"
t.string "teacher_education_graduation"
t.string "teacher_education_speciality"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "teacher_phones", :force => true do |t|
t.integer "teacher_id"
t.string "teacher_home_number"
t.string "teacher_mobile_number"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "teachers", :force => true do |t|
t.integer "user_id"
t.string "teacher_last_name"
t.string "teacher_first_name"
t.string "teacher_middle_name"
t.date "teacher_birthday"
t.string "teacher_sex"
t.string "teacher_category"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "users", :force => true do |t|
t.string "user_login"
t.string "user_role"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.string "encrypted_password"
t.string "salt"
end
If you are constructing your form properly to support the nested attributes then this is all you need:
user = User.new( params[:user] )
user.user_role = "teacher"
if user.save
...
end
The accepts_nested_attributes mechanics will take care of the rest. If the above doesn't work then lets look at how your form is put together.
I followed the tutorial here and everything turned out nicely.. until I tried adding attr_accessible to the article model. Thanks in advance.
Here's the related code:
app/models/user.rb
class User < ActiveRecord::Base
attr_accessible :name, :email
has_many :assets, :dependent => :destroy
accepts_nested_attributes_for :assets, :allow_destroy => true
end
app/models/asset.rb
class Asset < ActiveRecord::Base
attr_accessible :user_id, :image
belongs_to :user
has_attached_file :image,
:styles => {
:thumb=> "100x100#",
:small => "300x300>",
:large => "600x600>"
}
end
db/schema.rb
create_table "assets", :force => true do |t|
t.integer "user_id"
t.datetime "created_at"
t.datetime "updated_at"
t.string "image_file_name"
t.string "image_content_type"
t.integer "image_file_size"
end
create_table "users", :force => true do |t|
t.string "name"
t.string "email"
t.datetime "created_at"
t.datetime "updated_at"
end
app/views/users/_form.html.erb
<%= form_for(#user, :html => { :multipart => true }) do |f| %>
<% if #user.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#user.errors.count, "error") %> prohibited this user from being saved:</h2>
<ul>
<% #user.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :name %><br />
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :email %><br />
<%= f.text_field :email %>
</div>
<div class="newPaperclipFiles">
<%= f.fields_for :assets do |asset| %>
<% if asset.object.new_record? %>
<%= asset.file_field :image %>
<% end %>
<% end %>
</div>
<div class="existingPaperclipFiles">
<% f.fields_for :assets do |asset| %>
<% unless asset.object.new_record? %>
<div class="thumbnail">
<%= link_to( image_tag(asset.object.image.url(:thumb)), asset.object.image.url(:original) ) %>
<%= asset.check_box :_destroy %>
</div>
<% end %>
<% end %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
After trying various permutations and going through related posts, finally caught the gremblin that's been eluding me the past few days. All I needed is to add the :assets_attributes to the list of attr_accessible in the user model. Thanks for reading!
attr_accesible for nested objects