Rails nested form not rendering - ruby-on-rails

I'm guessing this is more of a fundamental issue than the form simply "not rendering", but here it goes. I'll try to keep this brief but a fair amount of context may be needed.
I'm making a custom Rolodex app and the organization gave me specific things to include. For this specific problem I'm dealing with contact emails only. Ideally I would have a system like Google Contact's, where you can click to add another email field and there's a dropdown to select a category (Home, Work, etc.).
In this case the categories are coming from a table called categories. Here is a link to the entity relationship diagram I made for the entire project (not just emails): http://i.imgur.com/LNSWZHy.jpg
To sum things up: How do I set things up to allow the entry of emails during a contact creation/edit?
Here's my relevant code:
models/contact.rb
class Contact < ActiveRecord::Base
has_many :emails
accepts_nested_attributes_for :emails
end
models/email.rb
class Email < ActiveRecord::Base
belongs_to :contact
belongs_to :category
end
controllers/contacts_controller.rb
# GET /contacts/new
def new
#contact = Contact.new
#email = #contact.emails.build(params[:email])
end
views/contacts/_form.html.erb
<%= form_for(#contact) do |f| %>
#Other contact fields here
<% f.fields_for #email do |email| %>
<div class="field">
<%= email.label :category_id %><br>
<%= email.text_field :category_id %><br/>
</div>
<div class="field">
<%= email.label :email %><br>
<%= email.text_field :email %><br/>
</div>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
I also confirmed that this whole setup works "manually". I can make contacts and categories, and then properly reference them when creating a new email by manually putting in the foreign ids. The issue here is a matter of condensing this process into one form.
Any input would be appreciated, thanks!

Change:
<% f.fields_for #email do |email| %>
into
<%= f.fields_for #email do |email| %>

Related

Writing Nested Form in RoR

I'm trying to write a nested form in ROR.
I have two tables Employee and EmployeeInfo and both table have a column named employeeID
these tables are connected with this key.
What i want to do is to create a form with some input fields which should update the values into both tables.
for eg i want a form which can create or update fields named employee_name, age, address and city But employee_name and age are present in table Employee and city and address are present in table EmployeeInfo.
So how should i write the form tag inorder to do this.
Please be sorry if question is a blunder. I'm realy new to this. Pls help
Extending #emu's answer
Models setup
#employee.rb
Class Employee < ActiveRecord::Base
has_one :employe_info
accepts_nested_attributes_for :employee_info
end
#employee_info.rb
Class EmployeeInfo < ActiveRecord::Base
belongs_to :employee
end
Controller
Class EmployeesController < ApplicationController
def new
#employee = Employee.new
#employee.build_employee_info
end
def create
#employee = Employee.new(employee_params)
if #employee.save
redirect_to #employee
else
render 'new'
end
end
private
def employee_params
params.require(:employee).permit(:employee_name, :age, employee_info_attributes: [:id, :city,:address])
end
end
In rails 4 you need to use
accepts_nested_attributes_for :employeeinfo
in your employee model. And also employee has the relation with emplyeeinfo is has_one.
in the form:
<%= form_for #employe, :html => { :multipart => true } do |f| %>
<% if #employe.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#employe.errors.count, "error") %> prohibited this employe from being saved:</h2>
<ul>
<% #employe.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :employee_name %><br>
<%= f.text_field :employee_name %>
</div>
<div class="field">
<%= f.label :age %><br>
<%= f.text_field :age %>
</div>
<%= f.fields_for :employeeinfo do |s| %>
<%= s.label :address %><br>
<%= s.text_field :address %>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Please edit the form objects according to your model name.
Foriegn Key
Firstly the "connector" key you're referring to is called a foreign_key.
This is a standard relational database feature, allowing you to "join" two or more databases together with a single reference point. Whenever you use associations in Rails, you'll basically have to join the two datatables with a foreign_key
both table have a column named employeeID
Your employee_infos table only needs to have the foreign_key employee_id:
#app/models/employee.rb
Class Employee < ActiveRecord::Base
has_one :employee_info #-> foreign key = "employee_id"
accepts_nested_attributes_for :employee_info
end
#app/models/employee_info.rb
Class EmployeeInfo < ActiveRecord::Base
belongs_to :employee
end
Forms
As mentioned by Emu, you'll need to use accepts_nested_attributes_for
This allows you to pass data from a "parent" model to a child model, exactly what you have set up currently. The difference being you have to ensure you have it set up correctly.
Regardless of what you think, this is how you need to do it. You mention yourself that you're very new to Rails; which means your objections are likely based on your current DB setup. This might not be correct
You should use emu & Pavan's answers to fix this :)

At least one text_field must be filled

I have 3 text_fields in my view in which I enter students name. Of course you can enter one student or three students but I want to make sure that at least one student was provided because a project must have a student assigned to it.
Here is my view:
<%= form_for #project, url: projects_path do |f| %>
<p>
<%= f.label :name, "Name" %>
<%= f.text_field :name %>
</p>
<p>
<%= f.fields_for :students do |s| %>
<%= s.label :name %>
<%= s.text_field :name %>
<% end %>
</p>
<p>
<%= f.submit "Submit" %>
</p>
<% end %>
And new method from Projects controller:
def new
#project = Project.new()
3.times do
student = #project.students.build
end
end
What I want to achieve is to check if at least one student was provided and if not just show alert or disable submiting.
Edit
Models used in this project:
class Student < ActiveRecord::Base
belongs_to :project
end
class Project < ActiveRecord::Base
has_many :students
accepts_nested_attributes_for :students
validate :validate_student_count
def validate_student_count
errors.add(:students, "at least one is required") if students.count < 1
end
end
Lots of very similar questions on the internet. Here's some examples: Validate the number of has_many items in Ruby on Rails and Validate that an object has one or more associated objects
Just add a custom validation rule as:
validate :validate_student_count
def validate_student_count
errors.add(:students, "at least one is required") if students.count < 1
end

Ruby on rails: Trouble creating an object with multiple associations

I am having a problem with creating an object with an association.
I have a Message model that belongs_to a job, and a user or runner. Inside my jobs/index.html I want to show a list of jobs with their corresponding messages and a form to create a new message for that particular job.
The problem is whenever I create a message, job_id stays nil. I am new to ruby on rails, so I still dont fully understand this stuff.
Here is part of my jobs/index.html (NOTE: not my actual code, I am in class so I just typed this up, may contain syntax errors).
<% #jobs.each do |job| %>
<p> <%= job.body %> </p>
<%= form_for job.messages do |f| %>
<%= f.label :body %>
<%= f.text_field :body %>
<%= f.submit %>
<% end %>
<%if job.messages.present? %>
<ul>
<% job.messages.each do |message| %>
<li>
<p> message.description <p>
</li>
<% end %>
</ul>
<% else %>
<p> No messages <p>
<% end %>
<% end %>
Here is the create method in message controller (NOTE: current_login can be a runner or user, they both share the same attributes)
def create
#message = current_login.messages.new(params[:message])
#message.save
end
Job controller index action
def index
#jobs = Job.all
end
Message model
class Message < ActiveRecord::Base
attr_accessible :description
belongs_to :user
belongs_to :runner
belongs_to :job
end
User model
class User < ActiveRecord::Base
attr_accessible :username
has_many :jobs
end
Runner model
class Runner < ActiveRecord::Base
attr_accessible :username
has_many :jobs
end
Job model
class Job < ActiveRecord::Base
attr_accessible :body
has_many :messages
belongs_to :user
belongs_to :runner
end
Whenever I submit the message form inside the jobs/index.html view, it seems to successfully create a message with user_id or runner_id successfully filled out (depending on who posted the message), but I am getting nil for the job_id attribute.
Since your message belongs to job, i think you should be creating the nested resources within the jobs form.
Your new controller function inside the jobs model should build the association like so:
def new
#job = Job.new(params[:job])
#message = #job.build_message
end
your create model just needs to save the parent model:
def create
#job = Job.create(params[:job])
end
For lots of detailed information on how to do this, watch this railscast: http://railscasts.com/episodes/196-nested-model-form-part-1
I should also add, if you are simply trying to add a message to an existing job, just pass the parameter for the job_id correctly in your form, AND make sure the job you're referencing actually exists.
To solve this problem, I decided to manually create the tie between the message and the job it belongs to through a hidden field in the form.
<%= form_for(#message) do |f| %>
<%= f.label :body, "Description" %>
<%= f.text_area :body %>
<%= f.hidden_field :job_id, value: job.id %>
<%= f.submit 'Create message', class: 'button small secondary' %>
<% end %>

Update fails for nested attributes when nested object is ActiveRecord subclass

I have ActiveRecord with a subclass and its associated with another ActiveRecord object.
I am able to create my object with nested attributes with a form with nested attributes no problem for a new object (following Ryan Bates rails cast - Thanks by the way :)). However when i do an update it fails to save the changes to either the main object or the related object when submitted
I have the following Activerecord classes and sub class.
class Room < ActiveRecord::Base
attr_accessible :name, :type, room_headers_attributes
has_many :room_headers, dependent: :destroy
accepts_nested_attributes_for :room_headers , :allow_destroy => true
end
And the sub class is
class BigRoom < Room
end
And the related class is
class RoomHeader < ActiveRecord::Base
attr_accessible :key, :room_id, :value
belongs_to :room
end
In my room controller I created the nested objects. note that i'm using :type to specify the subclass type
def new
#room = current_user.passes.build(params[:room])
#room.type = params[:type]
3.times do
room_header = #room.room_headers.build
end
....
end
....
def edit
#room = Room.find(params[:id])
end
def update
#room = Room.find(params[:id])
if #room.update_attributes(params[:room])
...
The form used for creating and editing is the same
<%= form_for(#room) do |f| %>
<div class="field">
<%= f.label :name %><br />
<%= f.text_field :name %>
</div>
<%= f.fields_for :room_headers do |builder| %>
<%= render 'room_header_fields', f: builder %>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end &>
And the _room_headers.html.erb partial is
<p class="fields">
<%= f.label :key, "Key" %>
<%= f.text_field :key %>
<%= f.label :value, "Value" %>
<%= f.text_field :value %>
<%= f.check_box :_destroy %>
<%= f.label :_destroy, "Remove Header" %>
</p>
To recap on the problem. I can successfully create a new BigRoom. In the new form when i create the BigRoom and I can successfully set values for the RoomHeader class and these are all saved successfully.
However when i Edit the the record and submit changes for update, nothing is saved. Either for changes for the Bigroom attributes or to the associated RoomHeader records.
first try by
if #room.update_attribute(params[:room])
rather
if #room.update_attributes(params[:room])
if this works then their are some errors with your validdations
Ok, nested attributes were a red herring. The problem is with STI
The Rails form helper guide says you can’t rely on record identification with STI.
In the form_for we need to coearce the ids to be the base type id otherwise the edit fails
so
<%= form_for(#room) do |f| %>
should be
<%= form_for(#room.becomes(Room) do |f| %>
if you look at the difference in the html output
the problem html would create ids like big_room_fieldname when in edit mode
when using .becomes we get ids like room_fieldname. in whihc case it saves and updates ok

Nested model form not submitting everything

I heard about this community while listening to Hypercritical and I am excited to join in with my first question. I am working on my first rails App and I have run into an issue that I cannot seem to crack. I have been watching Railscast, Lynda.com, and Googling for days but I still cannot comprehend how to create a form that that will update my has_many :through associations at once. Allow me to try an explain what I am doing.
My Goal:
The firm I work for provides many "Service Offerings" and I want to be able to create a new service offering on one page and have it create the contacts and other information that is associated with it. The additional information such as "contacts" will live in their own tables because they may need to be referenced by many "Service Offerings."
Problem:
When I submit the form the "Service Offering" fields submit and are entered into the database, but the fields for the "Business Developer" do not. Obviously, I would like everything to be entered into its appropriate table and the for the IDs to be linked in the join table. I would really appreciate any insight that you could provide.
What I Have So Far: What you see below is Service Offerings and Business Developers. Eventually I will be adding Contacts, Photos, and Files but I thought I would start simply and work my way up.
Models:
class ServiceOffering < ActiveRecord::Base
attr_accessible :name, :description
has_many :business_developer_service_offerings
has_many :business_developers, :through => :business_developer_service_offerings
accepts_nested_attributes_for :business_developer_service_offerings
end
class BusinessDeveloper < ActiveRecord::Base
attr_accessible :first_name, :last_name
has_many :business_developer_service_offerings
has_many :service_offerings, :through => :business_developer_service_offerings
end
class BusinessDeveloperServiceOffering < ActiveRecord::Base
belongs_to :business_developer
belongs_to :service_offering
end
Controller:
def new
#service_offering = ServiceOffering.new
#service_offering.business_developers.build
end
def create
#service_offering = ServiceOffering.new(params[:service_offering])
if #service_offering.save
redirect_to(:action => 'list')
else
render('new')
end
end
View:
<%= form_for((#service_offering), :url => {:action => 'create'}) do |f|%>
<p>
<%= f.label :name%>
<%= f.text_field :name %>
<%= f.label :description%>
<%= f.text_field :description %>
</p>
<%= f.fields_for :business_developer do |builder| %>
<p>
<%= builder.label :first_name%>
<%= builder.text_field :first_name %>
<%= builder.label :last_name%>
<%= builder.text_field :last_name %>
</p>
<%end%>
<%= f.submit "Submit" %>
<%end%>
I figured it out. It turns out a few things were wrong and needed to be changed in addition to the two suggestions #Delba made.
The Form:
I took a look at RailsCasts #196 again and noticed that my form looked different than the one used there, so I tried to match it up:
<%= form_for #service_offering do |f|%>
<p>
<%= f.label :name%>
<%= f.text_field :name %>
<%= f.label :description %>
<%= f.text_field :description %>
</p>
<%= f.fields_for :business_developers do |builder| %>
<p>
<%= builder.label :first_name %>
<%= builder.text_field :first_name %>
<%= builder.label :last_name %>
<%= builder.text_field :last_name %>
</p>
<%end%>
<%= f.submit "Submit" %>
<%end%>
Initially, this presented an error:
undefined method `service_offerings_path'
Routes:
This lead me to learn about RESTful Routes because I was using the old routing style:
match ':controller(/:action(/:id(.:format)))'
So I updated my routes to the new RESTful Routes style:
get "service_offerings/list"
resource :service_offerings
resource :business_developers
attr_accessible:
That got the form visible but it was still not working. So I did some searching around on this site and found this post that talked about adding "something_attributes" to your parent objects model under attr_accessible. So I did:
class ServiceOffering < ActiveRecord::Base
has_many :business_developer_service_offerings
has_many :business_developers, :through => :business_developer_service_offerings
accepts_nested_attributes_for :business_developers
attr_accessible :name, :description, :business_developers_attributes
end
That change along with #Delba's suggestion shown in the above model and controller listed below solved it.
def new
#service_offering = ServiceOffering.new
#business_developer = #service_offering.business_developers.build
end
You just forgot to assign #business_developper.
def new
#service_offering = ServiceOffering.new
#business_developper = #service_offering.business_developpers.build
end
-
#business_developer = #service_offering.business_developers.build
initializes an instance of biz_dev which is then available in the view.
fields_for :biz_dev isn't really tied to this instance but to the many-to-many relationship btw serv_off and biz_dev.
In this way, you can add multiple input for additional biz_dev if you initialize another biz_dev instance in your controller. For instance:
5.times { #service_offering.biz_dev.build }
will add additional fields in your form without you having to declare them in your view.
I hope it helped.

Resources