I have some troubles with :reject_if. I don't know why the following code doesn't work.
View - _form.html.erb:
<%= f.fields_for :questions do |builder| %>
<div class="nested-field">
<%= builder.label :id, "Question" %><br />
<%= builder.collection_select(:id, Question.all(:order => 'question'), :id, :question, { :prompt => 'Select Question' } ) %>
</div>
<div class="nested-field">
<%= builder.label :test1 %><br />
<%= builder.text_field :test1 %>
</div>
<div class="nested-field">
<%= builder.label :test2 %><br />
<%= builder.text_field :test2 %>
</div>
<div class="nested-field">
<%= builder.label :description %><br />
<%= builder.text_field :description %>
</div>
<br /><br /><br />
<hr />
<% end %>
Model - questionary.rb:
has_many :questions, :dependent => :destroy
accepts_nested_attributes_for :questions, :reject_if => lambda { |a| a[:id].blank? }, :allow_destroy => true
Thank you very much!
Instead of
:reject_if => lambda { |a| a[:id].blank? }
try
:reject_if => lambda { |a| a['id'].blank? }
(note the string 'id') and to follow the API exactly, use proc
:reject_if => proc { |a| a['id'].blank? }
I had a look at the API for accepts_nested_attributes_for, and found there that the documentation states:
:reject_if
Allows you to specify a Proc or a Symbol pointing to a method that checks whether a record should be built for a certain attribute hash.
Have you tried to replace the lambda with proc? The syntax here seems to be special, so the lambda may be just ignored.
Related
Rails 5.0.1
Devise 4.2.0
Hello, I'm building an app in which the user must fill a form to sign up, which includes the registration info for devise, and some personal info por their profile. I have made the models for user and profile, established their one to one relation, and added accept_nested_attributes_for :profile inside the user. I have also modified the registrations views to include f.fields_for for the profile, and until that point everything seems to work fine.
But, when I try to create a new user, and fill the required information, I get an error inside the view (from devise I guess) saying:
1 error prohibited this user from being saved
Profile user must exist
I have already followed many guides on how to create a nested form with devise, and none of them seem to have this issue, and I have also searched a lot with no answer. Here are some snippets from my registration controller, user and profile model, and registrations/new view:
registrations_controller
class Users::RegistrationsController < Devise::RegistrationsController
before_action :configure_sign_up_params, only: [:create]
before_action :configure_account_update_params, only: [:update]
def new
build_resources({})
resource.build_profile
respond_with self.resource
end
protected
def configure_sign_up_params
devise_parameter_sanitizer.permit(:sign_up,
keys: [:email, :password,
:password_confirmation,
profile_attributes: [:name, :art_name,
:birth_date, :location]])
end
User model
class User < ApplicationRecord
has_one :profile, dependent: :destroy
before_create :build_profile
accepts_nested_attributes_for :profile
# Devise configuration.....
end
Profile model
class Profile < ApplicationRecord
belongs_to :user
end
Registrations/new view
<h2>Nueva Cuenta</h2>
<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
<%= devise_error_messages! %>
<%= f.fields_for :profile do |b| %>
<div class="field">
<%= b.label :name, "Nombre" %><br />
<%= b.text_field :name %>
</div>
<div class="field">
<%= b.label :art_name, "Nombre artistico" %><br />
<%= b.text_field :art_name %>
</div>
<div class="field">
<%= b.label :birth_date, "Fecha de nacimiento" %><br />
<%= b.date_field :birth_date %>
</div>
<div class="field">
<%= b.label :location, "Ubicacion" %><br />
<%= b.text_field :location %>
</div>
<% end %>
<div class="field">
<%= f.label :email %><br />
<%= f.email_field :email, autofocus: true %>
</div>
<div class="field">
<%= f.label :password %>
<% if #minimum_password_length %>
<em>(<%= #minimum_password_length %> characters minimum)</em>
<% end %><br />
<%= f.password_field :password, autocomplete: "off" %>
</div>
<div class="field">
<%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation, autocomplete: "off" %>
</div>
<div class="actions">
<%= f.submit "Sign up" %>
</div>
<% end %>
<%= render "devise/shared/links" %>
My guess is that it has something to do with the sanitizers, I'm not completely sure how do I pass each attribute through, since most of the guides that explained this did with an older version of devise.
Thanks for your attention.
in your profile model, try this:
belongs_to :user, optional: true
it works for me
I am making a polymorphic association with devise and simple for but for some reason i cant get the params to work
here is my code:
User:
class User < ActiveRecord::Base
devise :database_authenticatable,
:rememberable, :trackable, :validatable
belongs_to :loginable, polymorphic: true
end
Designer:
class Designer < ActiveRecord::Base
has_one :user, as: :loginable
accepts_nested_attributes_for :user
end
Layout:
<%= simple_form_for [:admin, #designer] , :html => { :class => 'form-horizontal' } do |f| %>
<% if f.error_notification %>
<div class="alert alert-error fade in">
<a class="close" data-dismiss="alert" href="#">×</a>
<%= f.error_notification %>
<% if #designer.errors.any? %>
<ul>
<% #designer.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
<% end %>
</div>
<% end %>
<div class="control-group">
<%= f.label :profile_name, :class => 'control-label' %>
<div class="controls">
<%= f.text_field :profile_name, :class => 'text_field' %>
</div>
</div>
<%= f.simple_fields_for users do |u| %>
<div class="control-group">
<%= u.label :email, :class => 'control-label' %>
<div class="controls">
<%= u.text_field :email, :class => 'text_field' %>
</div>
</div>
<div class="control-group">
<%= u.label :password, :class => 'control-label' %>
<div class="controls">
<%= u.password_field :password, :class => 'text_field' %>
</div>
</div>
<div class="control-group">
<%= u.label :type, :class => 'control-label' %>
<div class="controls">
<%= u.input :role, :label => false do %>
<%= u.select :role_id, Role.all.map { |r| [r.name, r.id] } %>
<% end %>
</div>
</div>
<div class="control-group">
<%= u.label :firstname, :class => 'control-label' %>
<div class="controls">
<%= u.text_field :firstname, :class => 'text_field' %>
</div>
</div>
<% end %>
<div class="form-actions">
<%= f.submit nil, :class => 'btn btn-primary' %>
</div>
<% end %>
Controller:
def create
#user = User.new(designer_params)
#designer = Designer.new(designer_params)
#user.loginable = #designer
respond_to do |format|
if #user.save! && #designer.save!
format.html { redirect_to admin_designers_path, notice: 'Designer was successfully created.' }
format.json { render action: 'show', status: :created, location: admin_designer_path(#designer) }
else
format.html { render action: 'new' }
format.json { render json: [designer: #designer.errors, user: #user.errors], status: :unprocessable_entity }
end
end
end
def designer_params
params.permit(:profile_name, :user, user_attributes: [:email, :password, :password, :firstname, :lastname, :address, :postalcode, :city, :country, :role, :role_id])
end
My params seems to ignore the user attributes, i only see profile name for some reason.
Any ideas on how to fix this would be greatly appreciated
Thanks!
I managed to resolve my own issues. so i am posting the answer hoping to save someone else lots of time.
i ended up creating another private method for the user params
def designer_params
params.require(:designer).permit(:profile_name, user_attributes: [:email, :password, :password, :firstname, :lastname, :address, :postalcode, :city, :country, :role, :role_id])
end
def user_params
params[:designer][:user_attributes].permit(:email, :password, :password, :firstname, :lastname, :address, :postalcode, :city, :country, :role, :role_id)
end
and then using those to create my relationship
def create
#designer = Designer.new(designer_params)
#user = User.new(user_params)
#user.loginable = #designer
#designer.save!
end
also if you are having trouble viewing the nested form make sure to use the
build_ method
def new
#designer = Designer.new
#user = #designer.build_user
end
In my rails app, I am creating an object "Organization" and two sub-objects "User" and "Settings" in a nested form. When I run the form I get the error:
WARNING: Can't mass-assign protected attributes: user
I had previously had this problem on another project and discovered I needed the
#organization.users.build
in organizations_controller/new. In order to have the sub-objected added to and create a a sub-object on submittal of the form.
organization.rb
class Organization < ActiveRecord::Base
attr_accessible :org_name, :address1, :address2, :city, :state, :postal_code, :country, :logo_image, :setting_id, :active, :status_image, :users_attributes, :setting_attributes
has_many :users, :dependent => :destroy
has_one :setting, :dependent => :destroy
accepts_nested_attributes_for :users
accepts_nested_attributes_for :setting
end
user.rb
class User < ActiveRecord::Base
attr_accessible :email, :password, :password_confirmation, :name_first, :name_last, :admin, :notes, :current_outstanding, :pin, :registered, :sms, :super_user, :organization_id
belongs_to :organization
end
setting.rb
class Setting < ActiveRecord::Base
attr_accessible :green_hours, :green_mins, :yellow_hours, :yellow_mins, :red_hours, :red_mins, :reminder_sms, :reminder_sms_hours, :reminder_sms_mins, :logo_url, :comp_name, :alert_emails, :alert_smss, :history_hours, :time_zone, :user_id, :organization_id
belongs_to :organization
end
organizations_controller.rb
class OrganizationsController < ApplicationController
def new
#organization = Organization.new
#organization.build_setting
#organization.users.build
respond_to do |format|
format.html { render :layout => 'application_dashboard_orgs' }
format.json { render json: #organization }
end
end
def create
#organization = Organization.new(params[:organization])
respond_to do |format|
if #organization.save
format.html { redirect_to organizations_path, notice: 'Organization was successfully created.' }
format.json { render json: #organization, status: :created, location: #organization }
else
format.html { render action: "new" }
format.json { render json: #organization.errors, status: :unprocessable_entity }
end
end
end
end
organizations/_form.html.erb
<%= form_for(#organization) do |f| %>
<div class="Col1">
<div class="MenuItem"><div class="MenuItemLabel">Account Name:</div> <%= f.text_field :org_name %></div>
<div class="MenuItem"><div class="MenuItemLabel">Address Line 1:</div> <%= f.text_field :address1 %></div>
<div class="MenuItem"><div class="MenuItemLabel">Address Line 2:</div> <%= f.text_field :address2 %></div>
<div class="MenuItem"><div class="MenuItemLabel">City:</div> <%= f.text_field :city %></div>
<div class="MenuItem"><div class="MenuItemLabel">State:</div> <%= f.text_field :state %></div>
<div class="MenuItem"><div class="MenuItemLabel">Postal Code:</div> <%= f.text_field :postal_code %></div>
<div class="MenuItem"><div class="MenuItemLabel">Country:</div> <%= f.text_field :country %></div>
<div class="MenuItem"><div class="MenuItemLabel">Logo Image:</div> <%= f.file_field :logo_image %></div>
<div class="MenuItem"><div class="MenuItemLabel">Active Account?</div> <%= f.check_box :active %></div>
</div>
<div class="Col2">
<div class="MenuItem"><div class="MenuItemLabel"><b>Administrator Account</b></div></div>
<%= f.fields_for :user do |user| %>
<div class="MenuItem"><div class="MenuItemLabel">First Name:</div> <%= user.text_field :name_first %></div>
<div class="MenuItem"><div class="MenuItemLabel">Last Name:</div> <%= user.text_field :name_last %></div>
<div class="MenuItem"><div class="MenuItemLabel">Email Address:</div><%= user.text_field :email %></div>
<div class="MenuItem"><div class="MenuItemLabel">PIN:</div><%= user.password_field :password, :id => "password_field", :onchange => "add_pin()" %></div>
<div class="MenuItem"><div class="MenuItemLabel">PIN Confirmation:</div><%= user.password_field :password_confirmation %> </div>
<div class="MenuItem"><div class="MenuItemLabel">SMS Reminder Phone #:</div><%= user.text_field :sms %> </div>
<div class="MenuItem"><div class="MenuItemLabel">Is Administrator:</div> <%= user.check_box :admin, {checked: true} %></div>
<div class="MenuItem"><div class="MenuItemLabel">Password Setup?</div> <%= user.check_box :registered %></div>
<% end %>
<%= f.fields_for :setting do |setting| %>
<%= setting.hidden_field :green_hours, :value => params[99] %>
<%= setting.hidden_field :green_mins, :value => params[59] %>
<%= setting.hidden_field :yellow_hours, :value => params[0] %>
<%= setting.hidden_field :yellow_mins, :value => params[15] %>
<%= setting.hidden_field :red_hours, :value => params[0] %>
<%= setting.hidden_field :red_mins, :value => params[0] %>
<%= setting.hidden_field :reminder_sms, :value => params[true] %>
<%= setting.hidden_field :reminder_sms_hours, :value => params[0] %>
<%= setting.hidden_field :reminder_sms_mins, :value => params[15] %>
<%= setting.hidden_field :history_hours, :value => params[24] %>
<% end %>
<div class="MenuItem">
<%= flash[:notice] %> <br />
<%= f.submit "Save Settings" %> <!--<input type="reset" value="Reset" /> -->
</div>
<div class="clr"></div>
</div>
<%= f.fields_for :user do |user| %>
should be
<%= f.fields_for :users do |user| %>
I think what you want to do is use a form backed object. Jeff Dean has a good blog post on this at http://pivotallabs.com/users/jdean/blog/articles/1706-form-backing-objects-for-fun-and-profit
Your error indicates that you don't have the ability to set the "user" attribute when you try to save your organization. Try adding :user and :setting to your attr_accessible line in organization.rb
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
I'm using nested_attributes and trying to implement the add/remove fields on-the-fly throu ajax following Ryan Bates screencast about Nested Model (#196)
Doing this, it won't work, but when removing the "link_to_add_fields" line, it works fine.
The problem is that I'm don't know if I doing this all associations right.
<%= form_for(#item) do |f| %>
<% if #item.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#item.errors.count, "error") %> prohibited this item from being saved:</h2>
<ul>
<% #item.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :title %><br />
<%= f.text_field :title %>
</div>
<div class="field">
<%= f.label :item_type_id %><br />
<%= f.select :item_type_id, #item_types.collect { |p| [ p.title, p.id ]} %>
<br />
<%= f.fields_for :item_parts do |parts_form| %>
<%= render "item_part_fields", :p => parts_form %>
<% end %>
</div>
<%= link_to_add_fields "Add Part", f, :part %>
<div class="actions">
<%= button_for "Save Item", :class => 'positive pill button', :button_type => 'submit' %>
</div>
<% end %>
Actually my models are:
"ItemPart" model:
class ItemPart < ActiveRecord::Base
belongs_to :item
belongs_to :part
end
"Item" model:
class Item < ActiveRecord::Base
belongs_to :item_type
has_many :item_parts
has_many :parts, :through => :item_parts
accepts_nested_attributes_for :item_parts, :allow_destroy => true
after_save :save_id
validates :title, :presence => true
def save_id
item_part_attributes = [ { :item_id => self.id } ]
end
end
"Part" model:
class Part < ActiveRecord::Base
has_one :part_type
has_many :item_parts
has_many :items, :through => :item_parts
end
The error I'm getting doing this way:
undefined method `klass' for nil:NilClass
Extracted source (around line #26):
23: <%= render "item_part_fields", :p => parts_form %>
24: <% end %>
25: </div>
26: <%= link_to_add_fields "Add Part", f, :item %>
27: <div class="actions">
Application trace
app/helpers/application_helper.rb:44:in `link_to_add_fields'
app/views/items/_form.html.erb:26:in `block in _app_views_items__form_html_erb__1418129287024756954_2169222480__3228169100620818569'
app/views/items/_form.html.erb:1:in `_app_views_items__form_html_erb__1418129287024756954_2169222480__3228169100620818569'
app/views/items/edit.html.erb:3:in `_app_views_items_edit_html_erb___1857878264245794505_2169270380_890290209246324491'
Application_helper.rb
def link_to_add_fields(name, f, association)
new_object = f.object.class.reflect_on_association(association).klass.new # error line :44
fields = f.fields_for(association, new_object, :child_index => "new_#{association}") do |builder|
render(association.to_s.singularize + "_fields", :f => builder)
end
link_to_function(name, "add_fields(this, '#{association}', '#{escape_javascript(fields)}')" )
end
After hours and hours doing tests and googling a lot, I get it finally solved.
Seems that I'd to use the same local variable name to render the partial used for the form_for and then use it again as a helper method parameter needed. (In this case, "f" variable.)
I pasting the cleaning working code below
<%= form_for(#item) do |f| %>
<p>
<%= f.label :title %><br />
<%= f.text_field :title %>
</p>
<p>
<%= f.label :item_type_id %><br />
<%= f.select :item_type_id, #item_types.collect { |p| [ p.title, p.id ]} %><br />
</p>
<p>
<%= f.fields_for :item_parts do |parts_form| %>
<%= render "item_part_fields", :f => parts_form %>
<% end %>
</p>
<p><%= link_to_add_fields "Add Part", f, :item_parts %></p>
<p><%= button_for "Save Item", :class => 'positive pill button', :button_type => 'submit' %></p>
<% end %>
Hope this going to help someone someday :)
There is a mistake in your add more button. This should be,
<p><%= link_to_add_fields "Add Part", f, :item_parts %></p>
The association name should be the table name on which have many relation is.