Nested form with complex model fails to create children - ruby-on-rails-3

I have a bit of a complex model association:
class Company < ActiveRecord::Base
has_many :roles, :dependent => :destroy
has_many :users, :through => :roles
end
class Role < ActiveRecord::Base
belongs_to :user
belongs_to :company
attr_accessor :roles_attributes
attr_accessible :roles_attributes, :active, :company_id, :role
validates_presence_of :company_id, :role
validates_uniqueness_of :user_id, :scope => :company_id, :message => "Users may only have one role per company."
end
class User < ActiveRecord::Base
has_many :roles, :dependent => :destroy
accepts_nested_attributes_for :roles, :allow_destroy => true
has_many :companies, :through => :roles
end
The intent here is that a single user (email address) could login under different companies with different permissions (roles) per company.
I have users nested under company and my update controller works fine but now I can't seem to get the new/create controller to work:
Controller:
def new
#user = User.new
#role = #user.roles.build.company_id = session[:company_id]
respond_to do |format|
format.html # new.html.erb
format.json { render json: #user }
end
end
def create
#user = User.new(params[:user])
respond_to do |format|
if #user.save
format.html { redirect_to #user, notice: 'User was successfully created.' }
format.json { render json: #user, status: :created, location: #user }
else
format.html { render action: "new" }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
and the View:
<%= simple_nested_form_for [:company, #user] do |f| %>
<fieldset>
<div class="form-horizontal">
<%= f.input :email %>
<%= f.input :name_first %>
<%= f.input :name_last %>
<%= f.input :title %>
<%= f.input :phone %>
<%= f.input :mobile %>
<%= f.simple_fields_for :roles, #role do |role_form| %>
<%= role_form.hidden_field :company_id %>
<%= role_form.input :active %>
<%= role_form.input :role, :collection => [ "Guest", "User", "Inspector", "Owner"] %></td>
<% end %>
<%= f.input :notes, :input_html => { :rows => 5, :cols => 70 } %>
<div class="form-actions">
<%= f.submit nil, :class => 'btn btn-primary' %>
<%= link_to 'Cancel', company_users_path, :class => 'btn' %>
</div>
</fieldset>
<% end %>
When I submit the form it fails silently except that I notice in the logs that "roles_attributes" is being passed as:
"roles_attributes"=>{"0"=>{"company_id"=>"2", "active"=>"1", "role"=>"Inspector"}}
which I think should be:
"roles_attributes"=>[{"company_id"=>"2", "active"=>"1", "role"=>"Inspector"}]
I must be missing something obvious.

Turns out it was has_secure_password. I had deleted the password fields and the validation was failing.

Related

Rails nested attributes and has_many :through associations not showing fields_for

Here are my Models:
class Company < ActiveRecord::Base
has_many :roles, :dependent => :destroy, :inverse_of => :user
has_many :users, :through => :roles
validates :name, presence: true
end
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_many :roles, :dependent => :destroy, :inverse_of => :user
has_many :companies, :through => :roles
accepts_nested_attributes_for :roles, :limit => 1, :allow_destroy => true
end
class Role < ActiveRecord::Base
belongs_to :user, :inverse_of => :roles
belongs_to :company, :inverse_of => :roles
#accepts_nested_attributes_for :companies, :limit => 1, :allow_destroy => true
accepts_nested_attributes_for :company
end
The idea here is that Companies are unique and Users can be associated to multiple companies via a Role. I set up devise on the User model for authentication and signup. That was working fine and I could signup as a new user.
I want to add the company name to the signup process. I am trying a nested form:
<%= form_for(resource, :html => {:class => "form-signin" }, as: resource_name, url: registration_path(resource_name)) do |f| %>
<%= render partial: "shared/flash" %>
<%= devise_error_messages! %>
<h1 class="form-signin-heading text-muted">Register</h1>
<%= f.email_field :email, class: "form-control", placeholder: "Email", autofocus: true %>
<%= f.password_field :password, class: "form-control", placeholder: "Password", autocomplete: "off" %>
<%= f.password_field :password_confirmation, class: "form-control", placeholder: "Password Confirmation", autocomplete: "off" %>
<%= f.fields_for :roles do |r| %>
<%= r.fields_for :company do |c| %>
<%= c.text_field :name, class: "form-control", placeholder: "Company", autocomplete: "off" %>
<% end %>
<% end %>
<button class="btn btn-lg btn-primary btn-block" type="submit">
Register
</button>
<% end %>
I found some other SA answers that pointed out the need for the accepts_nested_attributes_for to be drilled down though the has_many through associations as well as some single/plural issues. After fixing those my form loads without errors except that the fields_for block is empty.
Now I will admit my models may be the issue here. I have copied the code from an app I worked on a few years ago so I have of lost track of why I did it this way.
At the end of the day I want to create the Company and Role when the user signs up. I planned to add the creation of the Role to the Company controller but I need to get to at least creating the company first.
UPDATE
I did some more digging and updated my form to this:
<% company = resource.companies.build %>
<%= f.fields_for :company, company do |c| %>
<%= c.text_field :name, class: "form-control", placeholder: "Company", autocomplete: "off" %>
<% end %>
I realized that my Devise controller was not building the nested Company resource. I wanted to stay away from a custom Devise controller. My form submits and my user is created but I am missing something here still because the Company and Role are not getting saved.
After some digging and experimentation here is how I resolved this:
Models
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_many :roles, :dependent => :destroy, :inverse_of => :user
has_many :companies, :through => :roles
accepts_nested_attributes_for :roles, :limit => 1, :allow_destroy => true
end
class Role < ActiveRecord::Base
belongs_to :user, :inverse_of => :roles
belongs_to :company, :inverse_of => :roles
accepts_nested_attributes_for :company
end
class Company < ActiveRecord::Base
has_many :roles, :dependent => :destroy, :inverse_of => :user
has_many :users, :through => :roles
validates :name, presence: true
end
Custom Devise Registration Controller
class RegistrationsController < Devise::RegistrationsController
# GET /resource/sign_up
def new
build_resource({})
#role = resource.roles.build(role: "owner", active: 1, default_role: 1)
#company = #role.build_company
set_minimum_password_length
yield resource if block_given?
respond_with self.resource
end
protected
def sign_up_params
params.require(:user).permit(:email, :password, :password_confirmation, roles_attributes: [ company_attributes: [ :id, :name ] ] )
end
end
HTML
<%= form_for(resource, :html => {:class => "form-signin" }, as: resource_name, url: registration_path(resource_name)) do |f| %>
<%= render partial: "shared/flash" %>
<%= devise_error_messages! %>
<h1 class="form-signin-heading text-muted">Register</h1>
<%= f.email_field :email, class: "form-control", placeholder: "Email", autofocus: true %>
<%= f.password_field :password, class: "form-control", placeholder: "Password", autocomplete: "off" %>
<%= f.password_field :password_confirmation, class: "form-control", placeholder: "Password Confirmation", autocomplete: "off" %>
<%= f.fields_for :roles, resource.roles.build do |r| %>
<%= r.fields_for :company, resource.roles.build.build_company do |c| %>
<%= c.text_field :name, class: "form-control", placeholder: "Company", autocomplete: "off" %>
<% end %>
<% end %>
<button class="btn btn-lg btn-primary btn-block" type="submit">
Register
</button>
<% end %>
I figured I had the models and associations messed up. Now the form_for works it's magic.
I am going to post another separate question but when I still can't figure out is:
Why does the #role and #company I set in the controller work in the view HTML?
How can I set the additional Role attributes? I tried during the build stage in both the controller and the view but it doesn't take.

Nested fields not being created on form

I am trying to get a Project form to build the first (starting) time of several (up to 12) volunteer time blocks.
project.rb
class Project < ActiveRecord::Base
attr_accessible :title, ...
has_many :vol_times, :dependent => destroy
accepts_nested_attributes_for :vol_times, :reject_if => lambda { |a| a[:start_time].blank? }, :allow_destroy => true
...
end
vol_time.rb
class Vol_time < ActiveRecord::Base
attr_accessible :start_time, ...
belongs_to :project
end
ProjectsController
class ProjectsController < ApplicationController
before_filter :signed_in_user, only: :create
...
def new
#project = Project.new
#user = current_user
#project.vol_times.build
end
...
end
Vol_Times Controller
class Vol_TimesController < ApplicationController
def new
#reward = Reward.new
end
...
end
My view looks like this...
<%= form_for(#project) do |f| %>
<div class="form_field_block">
<p class="form_label"> Project Title</p>
<%= f.text_field :title, :size => 40, :placeholder => " Project Title...", :class => "frm" %>
</div>
<div class="form_field_block">
<p class="form_label"> Project Sub-title</p>
<%= f.text_field :sub_title, :size => 40, :placeholder => " Project Sub-title...", :class => "frm" %>
</div>
<p class="clearing"></p>
<div class="form_field_block">
<% f.fields_for :vol_times do |builder| %>
<%= render :partial => 'start_time', :f => builder %>
<% end %>
</div>
<p class="clearing"></p>
<%= button_tag "btn_start_project.png", :class => "btn_save" %>
<% end %>
And the _partial looks like this...
<%= f.label :start_time, "Starting Time" %>
<%= f.text_field :start_time %>
When I view the page, I see the containing <div>, but not the contents of the ERB, which should be parsed from the _partial.
Any ideas why this isn't working? I got the general context from Ryan Bates' RailsCast #196 - Here
you are missing a = on the fields_for. It should be
<%= f.fields_for :vol_times do |builder| %>

Updating unused field after initial creation does not work rails

For reference, this is using Rails 3.0.9.
I can't seem to figure out why, but I cannot update a field which was left blank at the initial creation of the object/row.
If my model looks like this:
name - string
date - date
message - string
If I put info in all of the fields upon initial creation, everything can be updated without a hitch later on. But if I do not put info in one of the fields, say the title, I cannot update that field after initial creation.
I'm not doing anything out of the ordinary, the form is pretty plain jane:
<%= form_for #event do |f| %>
<%= f.error_messages %>
<p>
<%= f.label :name %><br />
<%= f.text_field :name %>
</p>
<p>
<%= f.label :date %><br />
<%= f.date_select :date %>
</p>
<p>
<%= f.label :message %><br />
<%= f.text_field :message %>
</p>
<p><%= f.submit %></p>
<% end %>
And my controller is equally as simple:
def update
if #event.update_attributes(params[:event])
redirect_to #event, :notice => "Successfully updated event."
else
render :action => 'edit'
end
end
And the model:
class Event < ActiveRecord::Base
has_many :races, :dependent => :destroy
has_many :price_groups, :dependent => :destroy
accepts_nested_attributes_for :races, :reject_if => lambda{ |a| a[:name].blank? }, :allow_destroy => true
accepts_nested_attributes_for :price_groups, :reject_if => lambda{ |a| a[:name].blank? }, :allow_destroy => true
attr_accessible :name, :date, :message, :races_attributes, :price_groups_attributes
end

Field_for in nested attributes is giving problem

I'm new to both programming and Ruby on Rails. I'm just trying with a sample 2 level deep nesting. When I followed Ryan's Scraps (http://ryandaigle.com/articles/2009/2/1/what-s-new-in-edge-rails-nested-attributes) for 1 level deep nesting everything well and good but when I extended for 2 level deep with following requirement:
Instead of creating parent, children and grandchildren at a time I want to create parent first then child and grandchild together.My code is
My model:
class Parent < ActiveRecord::Base
has_many :children
has_many :grand_children
accepts_nested_attributes_for :children, :allow_destroy => true
accepts_nested_attributes_for :grand_children, :allow_destroy => true
end
class Child < ActiveRecord::Base
belongs_to :parent
has_many :grand_children
accepts_nested_attributes_for :grand_children
end
class GrandChild < ActiveRecord::Base
belongs_to :parent
belongs_to :child
end
My children controller -new method:
def new
#parent = Parent.find(params[:parent_id])
child = Child.new
child.grand_children.build
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => #child }
end
end
My children _form template is
<%= form_for([#parent, #parent.children.build]) do |form| %>
<div>
<%= form.label :name %><br />
<%= form.text_field :name %>
</div>
<div class="field">
<%= form.label :sex %><br />
<%= form.text_field :sex %>
</div>
<div>
<%= form.fields_for :grand_children do |grand_child_form| %>
<%= render :partial => "grand_children/form", :locals => { :form => grand_child_form} %>
<% end %>
</div>
<% end %>
Here I'm not getting any error as such but when I select new child the grand_child is not appearing,
<%= form.fields_for :grand_children do |grand_child_form| %>
<%= render :partial => "grand_children/form", :locals => { :form => grand_child_form} %>
<% end %>
is not getting reflected at all .
Thanks in advance
Hey folks I got d solution by trial and error,
form template for children is
<div>
<%= form.fields_for :grandchildren, #grand_child do |grand_child_form| %>
<%= render :partial => "grandchildren/form", :locals => { :form => grand_child_form} %>
<% end %>
</div>

Problem saving data using Nested Attributes

I'm
I'm building a website on Ruby On Rails 3.0.7 and I want to save a store object and its languages. So, I have the following models:
class Store < ActiveRecord::Base
belongs_to :user
has_many :languages, :through => :store_languages
has_many :store_languages
accepts_nested_attributes_for :store_languages
#Validations
validates :title, :presence => true, :length => 5..100
validates :contact_email, :presence => true, :format => { :with => /^([^#\s]+)#((?:[-a-z0-9]+\.)+[a-z]{2,})$/i }
end
class Language < ActiveRecord::Base
has_many :stores, :through => :store_languages
has_many :store_languages
end
class StoreLanguage < ActiveRecord::Base
belongs_to :store
belongs_to :language
validates :store_id, :presence => true
validates :language_id, :presence => true
end
StoresController's relevant actions:
def new
#store = Store.new
#store.store_languages.build
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => #store }
end
end
# POST /stores
# POST /stores.xml
def create
#raise params.inspect
#store = current_user.stores.new(params[:store])
respond_to do |format|
if #store.save
format.html { redirect_to(#store, :notice => 'Store was successfully created.') }
format.xml { render :xml => #store, :status => :created, :location => #store }
else
#store.store_languages.build
format.html { render :action => "new" }
format.xml { render :xml => #store.errors, :status => :unprocessable_entity }
end
end
end
View: /stores/new.html.erb:
<%= form_for(#store) do |f| %>
<% if #store.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#store.errors.count, "error") %> prohibited this store from being saved:</h2>
<ul>
<% #store.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<p>
<label for="title">Title*</label><br />
<%= f.text_field :title %>
</p>
<p>
<label for="description">Description</label><br />
<%= f.text_field :description %>
</p>
<p>
<label for="contact_email">Contact E-mail*</label><br />
<%= f.text_field :contact_email %>
</p>
<p>
<label for="logo">Logo</label><br />
<%= f.file_field :logo %>
</p>
<% f.fields_for :store_languages do |lf| %>
<%= lf.collection_select :language_id, #languages, :id, :name, {}, {:multiple => true } %>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
So, I've got the following records in the languages table:
id | name
3 English
4 EspaƱol
What happens is that when I create a new store selecting the two languages from the list, it will save the following at the store_languages table:
id | store_id | language_id
4 4 1
And the language_id = 1 doesn't exist.
If I debug the application at the create action, I get the following:
"store"=>{"title"=>"asdasdsdsadasdasdasd", "description"=>"", "contact_email"=>"asdasdsa#asdasdsad.com", "logo"=>"", "store_languages_attributes"=>{"0"=>{"language_id"=>["3", "4"]}}}
You can see that the ids are correct here: 3 and 4. So, I don't know why it saves 1.
Any ideas?
Try
<%= lf.collection_select :language_ids, #languages, :id, :name, {}, {:multiple => true } %>
(ie using ids instead of id in the attribute name)