Unknown attribute 'user_id' with devise nested attributes - ruby-on-rails

I am using the Devise gem to authenticate users. I have a User model and an Address model relation where each User has_one :address and each address belongs_to :user. When I try to register a new user I get the following error on page load: unknown attribute: user_id. The trace points to the line <% resource.build_address... seen in my view.
If I just delete that line from my view the page will load but none of my nested form fields show up.
In Rails console I can create and save an address then use that saved address as an attribute for a new User that will save.
The view is as follows:
<% resource.build_address unless resource.address %>
<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name)) do |f| %>
<%= f.email_field :email, :autofocus => true, placeholder: "Your email", class: 'input-block-level' %><br>
<%= f.password_field :password, placeholder: "Password", class: 'input-block-level' %><br>
<%= f.password_field :password_confirmation, placeholder: "Confirm password", class: 'input-block-level' %><br>
<%= f.text_field :favorite_cuisine, placeholder: "Favorite cuisine", class: 'input-block-level' %><br>
<%= f.fields_for :address do |address_form| %>
<%= address_form.text_field :street_one, placeholder: "Street", class: 'input-block-level' %><br>
<%= address_form.text_field :street_two, placeholder: "Street #2", class: 'input-block-level' %><br>
<%= address_form.text_field :city, placeholder: "City", class: 'input-block-level' %><br>
<%= address_form.text_field :state, placeholder: "State", class: 'input-block-level' %><br>
<%= address_form.text_field :zip, placeholder: "zip", class: 'input-block-level' %><br>
<% end %>
<% end %>
My User model:
has_one :address, :dependent => :destroy
accepts_nested_attributes_for :address
# Include default devise modules. Others available are:
# :token_authenticatable, :confirmable,
# :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :password, :password_confirmation, :remember_me,
:favorite_cuisine, :username, :address
validates_presence_of :email
validates_presence_of :address
My Address model:
belongs_to :user
attr_accessible :city, :state, :street_one, :street_two, :zip, :user_id
validates_presence_of :city
validates_presence_of :state
validates_presence_of :street_one
validates_presence_of :zip
Where am I going wrong here?

rails g migration AddUserIdToAddresses
Then edit the file, and
def change
add_column :addresses, :user_id, :integer
end
then rake db:migrate

Try something like this:
<%= f.fields_for (resource.address || :address), ... %>
Because the form is nested, it should build a new one with form submission to my knowledge.

Related

Creating Profile for Devise users

So I took the steps described in Profile model for Devise users?
I'm using rails 4 and ruby 1.9.3p448
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
attr_accessible :email, :password, :password_confirmation, :remember_me, :profile_attributes
has_one :profile
accepts_nested_attributes_for :profile
protected
def profile
super || build_profile
end
end
#
class Profile < ActiveRecord::Base
belongs_to :user
attr_accessible :uname, :manager
end
#
<h2>Sign up...</h2>
<%= form_for resource, :as => resource_name, :url => registration_path(resource_name) do |f| %>
<%= devise_error_messages! %>
<div><%= f.label :email %><br />
<%= f.email_field :email, :autofocus => true %></div>
<div><%= f.label :password %><br />
<%= f.password_field :password %></div>
<div><%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation %></div>
<%= f.fields_for :profile do |profile_form| %>
<h2><%= profile_form.label :uname %></h2>
<p><%= profile_form.text_field :uname %></p>
<h2><%= profile_form.label :manager %></h2>
<p><%= profile_form.text_field :manager %></p>
<% end %>
<div><%= f.submit "Sign up" %></div>
<% end %>
<%= render "devise/shared/links" %>
#
Still can't save profile for user and this is the output:
Parameters: {"utf8"=>"✓", "authenticity_token"=>"kG7S9lF4+5hm+ggmKA4LZyXrN4hsPf01jGQvKxgzGGI=", "user"=>{"email"=>"test1#test.test", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]", "profile_attributes"=>{"uname"=>"1", "manager"=>"1"}}, "commit"=>"Sign up"} **Unpermitted parameters: profile_attributes**
Shoud I do anything in Profiles controller?
Thanks in advance
I found the solution!
In my users/registrations_controller.rb, I had to add the following
before_filter :configure_permitted_parameters, if: :devise_controller?
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) {|u|
u.permit(:email, :password, :password_confirmation, :remember_me,
profile_attributes: [:uname, :manager])}
end
and it works just fine!
Rails 4 has stopped using attr_accessible and has started using strong parameters -http://api.rubyonrails.org/classes/ActionController/StrongParameters.html
You'll need to add your nested attributes for profile into the permitted attributes in the user controller.

Can't mass-assign protected attributes devise error when using nested form

I have searched for quite a long, but could not found the solution. Here are my models:
web.rb
class Web < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
attr_accessible :email, :password, :password_confirmation, :user_type, :remember_me
belongs_to :role, :polymorphic => true
end
user.rb
class User < ActiveRecord::Base
has_one :web, :as => :role
attr_accessible :dob, :fname, :lname
end
org.rb
class Org < ActiveRecord::Base
has_one :web, :as => :role
attr_accessible :name, :website
end
Everything seems fine until i use the simple_form_for instead of normal form_for in the devise/registration/new.html.erb
<%= simple_form_for(resource, :as => resource_name, :url => registration_path(resource_name), :html => { :class => 'form-horizontal' }) do |f| %>
<%= f.input :email, label: false, :input_html => { :class => "span6", placeholder: "Email", type: "email", required: true}%>
<%= f.input :password, label: false, :input_html => { :class => "span6", placeholder: "Password", type: "password" }%>
<%= f.input :password_confirmation, label: false, :input_html => { :class => "span6", placeholder: "Re-enter Password", type: "password" }%>
<%= f.input :user_type, as: :hidden, :input_html => { :value => user_type} %>
<%= f.simple_fields_for resource.role do |rf| %>
<%= render :partial => "#{child_class_name.underscore}_fields", :locals => { :f => rf } %>
<% end %>
<%= f.submit "Sign up" %>
<% end %>
The nesting part puts the partial with appropriate model_fields name which contains corresponding fields.
*_org_fields.html.erb*
<%= f.text_field :name, :class=>"span6", :type=>"text", :placeholder=>"Name", :required=>"" %><br />
<%= f.text_field :website, :class=>"span6", :type=>"text", :placeholder=>"Website", :required=>"" %>
The problem is with the f.simple_fields_for, if i remove simple_ everything works fine. But i don't want it to be removed. The error i encounter is:
ActiveModel::MassAssignmentSecurity::Error in Devise::RegistrationsController#create
Can't mass-assign protected attributes: org
The request parameters are:
{"utf8"=>"✓",
"authenticity_token"=>"NnsyNdrrKJmd8QutqVs6HqZi0EnQmAmZF7zGYqnu+rI=",
"web"=>{"email"=>"",
"password"=>"[FILTERED]",
"password_confirmation"=>"[FILTERED]",
"user_type"=>"org",
"org"=>{"name"=>"",
"website"=>""}},
"commit"=>"Sign up"}
Please Help.
In Web, add:
attr_accessible :role_attributes
accepts_nested_attributes_for :role
Edit: Originally had it as User but Devise resource is Web.
Edit2: Missed the as: :role. Changed the attr values to reflect.

rails devise user external api

I am trying to setup a newsletter signup procedure when a new user signs up. I am using Mailchimp via gibbon to handle the newsletters. I have added a subscribe attribute to my model and a getter and setter method. I also have added the subscribe checkbox to my form. What I need to do is if the form box is checked subscribe the user to the email on creation.
model
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :token_authenticatable, :confirmable,
# :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :password, :password_confirmation, :remember_me, :username, :subscribe
validates :username, presence: true
validates_uniqueness_of :username
has_many :contest_entries, dependent: :destroy
has_many :votes, dependent: :destroy
def subscribe=(join)
puts "called subscribe with #{join}"
if join
Gibbon.new.list_subscribe(:id => "blah", :email_address => self.email)
end
end
def subscribe
subscribe ||= false
end
end
Form view
<h2>Sign up</h2>
<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name)) do |f| %>
<%= devise_error_messages! %>
<p><%= f.label :username %><br />
<%= f.text_field :username %></p>
<div><%= f.label :email %><br />
<%= f.email_field :email %></div>
<div><%= f.label :password %><br />
<%= f.password_field :password %></div>
<div><%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation %></div>
<div><%= f.label :subscribe, "Subscribe to Newsletter?" %><br />
<%= f.check_box :subscribe, :checked => true %></div>
<div><%= f.submit "Sign up" %></div>
<% end %>
<%= render "devise/shared/links" %>
I was hoping that by adding the attr_accessible and a method it would call the api from the contoller automatically, but it does not seem to be called.
Any advice on how to handle this? I could also use advice on how to test with RSPEC to make sure it is being called.
Thanks,
Cory
Ok I figured out the issue. The problem was with the check for join inside the setter method. Since it was a checkbox, I needed to check for a matching integer of 1.
def subscribe=(join)
begin
if join.to_i == 1
gb = Gibbon.new
result = gb.list_subscribe(:id => "blah", :email_address => self.email)
end
rescue
false
end
end

How to remove duplicate validation errors

I am having an issue with a sign up form. It was created with SimpleForm, authentication is done with Devise. When submitting the form, if the email or password is blank, it will display the error for this twice. In the user model there are presence validations for the first name, last name, profile name, password, and email. These duplicate errors only appear on the blank email and password fields. Any other blank fields will say so once.
Example:
# Errors Prohibited This User From Being Saved:
Email can't be blank
Email can't be blank
Password can't be blank
Password can't be blank
user.rb:
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
attr_accessible :email, :password, :password_confirmation, :remember_me, :first_name, :last_name, :profile_name
validates :first_name, :last_name, :email, :profile_name, :password, presence: true
validates :profile_name, uniqueness: true,
format: {
with: /^[a-zA-Z0-9_-]+$/
}
has_many :posts
def full_name
first_name + " " + last_name
end
end
registrations/new.html.erb:
<%= simple_form_for(resource, :as => resource_name, :url => registration_path(resource_name)) do |f| %>
<%= devise_error_messages! %>
<div class="formGroupLeft">
<%= f.input :first_name, :input_html => { :class => 'formGroupInput'} %>
</div>
<div class="formGroupRight">
<%= f.input :last_name, :input_html => { :class => 'formGroupInput'} %>
</div>
<div class="formGroupLeft">
<%= f.input :email, :input_html => { :class => 'formGroupInput'} %>
</div>
<div class="formGroupRight">
<%= f.input :profile_name, :input_html => { :class => 'formGroupInput'} %>
</div>
<div class="formGroupLeft">
<%= f.input :password, :input_html => { :class => 'formGroupInput'} %>
</div>
<div class="formGroupRight">
<%= f.input :password_confirmation, :input_html => { :class => 'formGroupInput'} %>
</div>
<div class="formActions">
<%= f.button :submit, "Sign Up" %>
</div>
<% end %>
Why might this be? And how can I attempt to fix it?
Looks like you've specified the devise validatable plugin, which adds email/password validations.
class User
devise :database_authenticatable, ... :validatable
end
Since you're specifying your own validations, I would omit the devise validatable plugin.

How to avoid "Can't mass-assign protected attributes" error

Even though I added accepts_nested_attributes_for to my model.
it still says "Can't mass-assign protected attributes"
What else am I supposed to do in order to avoid this???
models/user.rb
class User < ActiveRecord::Base
validates_presence_of :username
validates_uniqueness_of :username
validates_length_of :username, :within => 4..10
acts_as_messageable
has_one :user_profile
accepts_nested_attributes_for :user_profile
# Include default devise modules. Others available are:
# :token_authenticatable, :encryptable, :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable, :confirmable,
:recoverable, :rememberable, :trackable, :validatable
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :password, :password_confirmation, :remember_me, :username, :user_profile_attributes
def mailboxer_email(message)
email
end
# def name
# email
# end
end
models/user_profile.rb
class UserProfile < ActiveRecord::Base
belongs_to :user
accepts_nested_attributes_for :user
attr_accessible :nickname
end
views/registration/edit.html.erb
<h2>Edit <%= resource_name.to_s.humanize %></h2>
<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name), :html => { :method => :put }) do |f| %>
<%= devise_error_messages! %>
<div class="field">
<%= f.label :nickname %><br />
<%= f.fields_for :nickname_attributes, #user.user_profile do |user_profile| %>
<%= user_profile.text_field :nickname %>
<% end %>
</div>
<div><%= f.label :email %><br />
<%= f.email_field :email %></div>
<div><%= f.label :password %> <i>(leave blank if you don't want to change it)</i><br />
<%= f.password_field :password %></div>
<div><%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation %></div>
<div><%= f.label :current_password %> <i>(we need your current password to confirm your changes)</i><br />
<%= f.password_field :current_password %></div>
<%= recaptcha_tags :display => {:theme => 'red'} %>
<div><%= f.submit "Update" %></div>
<% end %>
<h3>Cancel my account</h3>
<p>Unhappy? <%= link_to "Cancel my account", registration_path(resource_name), :confirm => "Are you sure?", :method => :delete %>.</p>
<%= link_to "Back", :back %>
attr_accessible defines the attributes you want the user to be able to mass assign. Just make sure it has all the attributes you want in there.
To be fair, you can remove attr_accessible if you don't care about it and the error will disappear (but all your model fields will be mass assignable).
in edit.html.erb
wrong:
f.fields_for :nickname_attributes,
correct:
f.fields_for :user_profile_attributes,

Resources