Nested attributes form for model which belongs_to few models - ruby-on-rails

I have few models - User, Teacher and TeacherLeader.
class User < ActiveRecord::Base
attr_accessible ...,
:teacher_attributes
has_one :teacher
has_one :teacher_leader
accepts_nested_attributes_for :teacher_leader
end
class Teacher < ActiveRecord::Base
belongs_to :user
has_one :teacher_leader
end
class TeacherLeader < ActiveRecord::Base
belongs_to :user
belongs_to :teacher
end
I would like to fill TeacherLeader via nested attributes. So, i do such things in controller:
class TeacherLeadersController < ApplicationController
...
def new
#user = User.new
#teacher_leader = #user.build_teacher_leader
#teachers_collection = Teacher.all.collect do |t|
[ "#{t.teacher_last_name} #{t.teacher_first_name} #{t.teacher_middle_name}", t.id ]
end
#choosen_teacher = #teachers_collection.first.last unless #teachers_collection.empty?
end
end
And also have such view (new.html.erb):
<%= form_for #user, :url => teacher_leaders_url, :html => {:class => "form-horizontal"} do |f| %>
<%= field_set_tag do %>
<% f.fields_for :teacher_leader do |tl| %>
<div class="control-group">
<%= tl.label :teacher_id, "Teacher names", :class => "control-label" %>
<div class="controls">
<%= select_tag( :teacher_id,
options_for_select( #teachers_collection, #choosen_teacher )) %>
</div>
</div>
<% end %>
<% end %>
...
<%= f.submit "Create", :class => "btn btn-large btn-success" %>
<% end %>
Problem is that select form here does NOT appear. Why? Do i do something wrong?

<%= f.fields_for :teacher_leader do |tl| %>

Related

rails has_one through form

administrator.rb:
class Administrator < ActiveRecord::Base
has_one :administrator_role, dependent: :destroy
has_one :role, through: :administrator_role
end
role.rb:
class Role < ActiveRecord::Base
has_many :administrator_roles
has_many :administrators, through: :administrator_roles
end
administrator_role.rb:
class AdministratorRole < ActiveRecord::Base
belongs_to :administrator
belongs_to :role
end
in view for "new" action administrator_controller:
<%= form_for #administrator do |f| %>
<%= render 'shared/errors', object: #administrator %>
<div class="form-group">
<%= f.label :role_id, "Роль:" %>
<%= f.collection_select(:role_id, #roles, :id, :name) %>
</div>
...
<%= f.submit 'Save', class: 'btn btn-primary btn-lg' %>
<% end %>
administrator_controller.rb:
class AdministratorsController < ApplicationController
def new
#administrator = Administrator.new
#roles = Role.all
end
def create
#administrator = Administrator.new(administrators_params)
if #administrator.save
flash[:success] = "Account registered!"
redirect_to root_path
else
render :new
end
end
...
private
def administrators_params
params.require(:administrator).permit(:login, :password, :password_confirmation, :role_id)
end
end
when you open the page get the error:
undefined method `role_id' for #<Administrator:0x007f6ffc859b48>
Did you mean? role
How to fix it? if I put in place role_id a role, when you create administrator will get the error:
ActiveRecord::AssociationTypeMismatch (Role(#69964494936160) expected, got String(#12025960)):
You have to rewrite the form as below:
<%= form_for #administrator do |f| %>
<%= render 'shared/errors', object: #administrator %>
<div class="form-group">
<%= f.fields_for :role do |role_form| %
<%= role_form.label :role_id, "Роль:" %>
<%= role_form.select(:id, #roles.map { |role| [role.name, role.id] }) %>
<% end %>
</div>
...
<%= f.submit 'Save', class: 'btn btn-primary btn-lg' %>
<% end %>
You also need to add 1 line which enables the nested form logic as:
class Administrator < ActiveRecord::Base
has_one :administrator_role, dependent: :destroy
has_one :role, through: :administrator_role
accepts_nested_attributes_for :role
end
And also change the controller like:
class AdministratorsController < ApplicationController
#....
private
def administrators_params
params.require(:administrator).permit(
:login, :password,
:password_confirmation,
role_attributes: [ :id ]
)
end
end
When you are using has_one association, you get the below method, but not association_id=, and that is what error is saying.
association(force_reload = false)
association=(associate)
build_association(attributes = {})
create_association(attributes = {})
create_association!(attributes = {})

Rails 4.0 nested object forms not rendered

I have two models in my app: "WorkPost" and "Contacts".
WorkPost
class WorkPost < ActiveRecord::Base
has_one :contacts
end
Contacts
class Contacts < ActiveRecord::Base
belongs_to :work_post
end
In my controller's new method I do:
def new
#work_post = WorkPost.new
#work_post.contacts
end
And in view I create form:
<%= form_for(#work_post) do |f| %>
<div class="field">
<%= f.label 'Vacation' %><br>
<%= f.text_field :post_title, :placeholder => 'Vacation here' %>
</div>
<div class="field">
<%= f.label 'Vacation description' %><br>
<%= f.text_area :post_body, :placeholder => 'Vacation description here' %>
</div>
<% f.fields_for :contacts do |cf| %>
<div class="field">
<%= cf.label 'Email' %><br>
<%= cf.text_field :emails, :placeholder => 'Email here' %>
</div>
<% end %>
<div class="actions">
<%= f.submit "Post vacation", :class => 'btn_act' %>
</div>
<% end %>
But it seems like line <% f.fields_for :contacts do |cf| %> doesn't work.
Everything is rendered fine but email field.What I am doing wrong?
The problem is with this line
<% f.fields_for :contacts do |cf| %>
which should be
<%= f.fields_for :contact do |cf| %>
Also, the class name for the model and the association name for has_one/belongs_to should be singular.
#work_post.rb
class WorkPost < ActiveRecord::Base
has_one :contact #should be singular
end
#contact.rb
class Contact < ActiveRecord::Base #should be singular
belongs_to :work_post
end
Also, notice the change :contacts to :contact, as it is a has_one association.
Update:
Also, try the below changes
Include accepts_nested_attributes_for :contact in work_post.rb model
#work_post.rb
class WorkPost < ActiveRecord::Base
has_one :contact
accepts_nested_attributes_for :contact
end
Change the new method to below
def new
#work_post = WorkPost.new
#work_post.build_contact
end

Rails fields_for params blank

I'm trying to build a nested form for a survey and having problems with my params hash missing values from within the fields_for block.
I have the following models. The way the app works is that an admin creates a MiniPost and its MiniPostQuestions. Then a client creates a new MiniPostSurvey using one of the MiniPosts. The client then emails out SurveyInvites to users. When a user responds, a new SurveyResponse is created, along with a new QuestionAnswer for each MiniPostQuestion in the survey.
class MiniPost < ActiveRecord::Base
has_many :mini_post_questions
has_many :question_answers, through: :mini_post_questions
has_many :mini_post_surveys
belongs_to :employer
def questions
mini_post_questions
end
def surveys
mini_post_surveys
end
end
class MiniPostQuestion < ActiveRecord::Base
has_many :question_answers
belongs_to :mini_post
belongs_to :employer
def answers
question_answers
end
end
class MiniPostSurvey < ActiveRecord::Base
belongs_to :mini_post
belongs_to :employer
belongs_to :company
has_many :survey_invites
has_many :survey_responses, through: :survey_invites
def questions
mini_post.questions
end
end
class SurveyInvite < ActiveRecord::Base
belongs_to :mini_post_survey
has_many :survey_responses
def responses
survey_responses
end
end
class SurveyResponse < ActiveRecord::Base
belongs_to :survey_invite
has_many :question_answers
has_many :mini_post_questions, through: :question_answers
end
class QuestionAnswer < ActiveRecord::Base
belongs_to :survey_response
belongs_to :mini_post_question
validates :answer, presence: true
end
Here is my response form.
<div class="form-box">
<%= form_for #response, url: "/survey?key=#{#invite.key}", method: :post, html: { role: 'form' } do |f| %>
<% #questions.each do |question| %>
<div class="form-group">
<%= f.fields_for :mini_post_questions, question do |q| %>
<%= q.fields_for :question_answers, question.question_answers.build do |a| %>
<%= f.label question.question %>
<%= a.text_area :answer, class: 'form-control' %>
<%= a.hidden_field :survey_response_id, value: #survey.id %>
<% end %>
<% end %>
</div>
<% end %>
<div><%= f.submit "Submit", :class => "btn btn-primary" %></div>
<% end %>
</div>
My form renders correctly, however when I submit it, my params hash looks like this:
{"utf8"=>"✓",
"authenticity_token"=>"p8Tky2So10TH4FUUvLKhIh7j2vjNN39b3HDsF0cYE14=",
"survey_response"=>{"mini_post_questions"=>{"question_answers"=>{"answer"=>"", "survey_response_id"=>"11"}}},
"commit"=>"Submit",
"key"=>"e4fab42244db2286d471082696",
"controller"=>"surveys",
"action"=>"create"}
I would expect a mini_post_question key for each question, but I'm not sure how to get to that point.
I think you are on the right track, but you need to have your models accept nested attributes for the objects that you want in your form.
So I think in your SurveyResponse model, you would have
class SurveyResponse < ActiveRecord::Base
belongs_to :survey_invite
has_many :question_answers
accepts_nested_attributes_for :question_answers
has_many :mini_post_questions, through: :question_answers
end
Also, since it looks like you are not modifying the mini question here, I would say that you don't need to accept nested attributes for the questions, but just have a hidden field that assigns the mini_question_id to the question_answer
So your form should be something like this
<div class="form-box">
<%= form_for #response, url: "/survey?key=#{#invite.key}", method: :post, html: { role: 'form' } do |f| %>
<% #questions.each do |question| %>
<div class="form-group">
<%= f.fields_for :question_answers, #survey.question_answers.build do |q| %>
<%= q.label question.question %>
<%= q.text_area :answer, class: 'form-control' %>
<%= q.hidden_field :mini_post_question_id, value: question.id %>
<% end %>
</div>
<% end %>
<div><%= f.submit "Submit", :class => "btn btn-primary" %></div>
<% end %>
</div>
Since your form is accepting nested attributes for question_answers, you won't need to supply the survey_id.
This should get you closer to what you would need in your form.

Rails 4 fields_for not displaying field

I have two models that I would like to create with one form. I tried following this railscasts tutorial, but I just can't get the nested fields to display on the form. How can I make these nested fields appear?
Models
class Poll < ActiveRecord::Base
has_many :poll_answers, :dependent => :destroy
accepts_nested_attributes_for :poll_answers, allow_destroy: true
end
class PollAnswer < ActiveRecord::Base
belongs_to :poll
end
Controller
class PollsController < ApplicationController
def new
#poll = Poll.new
2.times { #poll.poll_answers.build }
end
private
def poll_params
params.require(:poll).permit([
:question,
poll_answers_attributes: [:answer]
])
end
end
View
<%= form_for(#poll) do |f| %>
<div class="field">
<%= f.label :question %><br>
<%= f.text_field :question %>
</div>
<% f.fields_for :poll_answers do |pa| %>
<p>Hello
<%= pa.text_field :answer %>
</p>
<% end %>
<%= debug #poll.poll_answers %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
You missed an =
<%= f.fields_for :poll_answers do |pa| %>
<p>Hello
<%= pa.text_field :answer %>
</p>
<% end %>

many-to-many with has_many :through association nested form

student.rb
class Student < ActiveRecord::Base
has_many :enrollments
has_many :courses, through: :enrollments
accepts_nested_attributes_for :enrollments
end
enrollment.rb
class Enrollment < ActiveRecord::Base
belongs_to :student
belongs_to :course
end
course.rb
class Course < ActiveRecord::Base
has_many :enrollments
has_many :students, through: :enrollments
end
enrollments_controller.rb
class EnrollmentsController < ApplicationController
def new
#current_student = current_user.student
#enrollments = #current_student.enrollments.build
end
def create
current_student = current_user.student
#enrollments = current_student.enrollments.build(enrollment_params)
if #enrollments.save
flash[:success] = "You have successfully enrolled."
redirect_to new_enrollment_path
else
# fail
flash[:danger] = "Please try again."
redirect_to new_enrollment_path
end
end
private
def enrollment_params
params.require(:enrollment).permit(:student_id, :course_id)
end
end
enrollment/new.html.erb
<%= nested_form_for(#current_student, html: { class: 'form-horizontal' }) do |f| %>
<%= f.fields_for :enrollments do |e| %>
<div class="form-group">
<%= e.label :course_id, for: :course_id, class: 'col-xs-3 control-label' %>
<div class="col-xs-9">
<%= e.collection_select :course_id, Course.all, :id, :name, {prompt: "Select your Course"}, {class: 'form-control'} %>
</div>
</div>
<% end %>
<%= f.link_to_add 'Add Course', :enrollments, class: "col-xs-9 col-xs-offset-3" %>
<div class="form-group">
<div class="col-xs-9 col-xs-offset-3">
<%= f.submit "Enroll Now", class: 'btn btn-primary' %>
</div>
</div>
<% end %>
By referering to :
many-to-many: has_many :through association form with data assigned to linking model create form view
Intention: Create the Enrollments with the existing courses and students.
Current implementation of enrollment/new.html.erb will show all of the existing enrollments on the form which is not the desired presentation view.
I wish to create a blank form for creating enrollments.
How can I do that?
By just adding a line, "!e.object.persisted?" it solves the problem.
enrollment/new.html.erb
<%= f.fields_for :enrollments do |e| %>
<!-- -->
<% if !e.object.persisted? %>
<div class="form-group">
<%= e.label :course_id, for: :course_id, class: 'col-xs-3 control-label' %>
<div class="col-xs-9">
<%= e.collection_select :course_id, Course.all, :id, :name, {prompt: "Select your Course"}, {class: 'form-control'} %>
</div>
</div>
<% end %>
<% end %>

Resources