I've been trying to add an account to a user for a couple of days now.
I've installed Devise with no problems, but now I wanted to add a Company Name field to my registration form.
Here's my code:
app/models/account.rb
class Account < ActiveRecord::Base
attr_accessible :name
has_many :users
accepts_nested_attributes_for :users
end
app/models/user.rb
class User < ActiveRecord::Base
belongs_to :account
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable, :confirmable
attr_accessible :first_name, :last_name, :account_attributes, :account, :email, :password, :password_confirmation, :remember_me
end
app/views/devise/registrations/new.html.erb
<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name)) do |f| %>
<%= devise_error_messages! %>
<div><%= f.label :first_name %><br />
<%= f.text_field :first_name %></div>
<div><%= f.label :last_name %><br />
<%= f.text_field :last_name %></div>
<%= f.fields_for :account do |account_form| %>
<div><%= account_form.label :name %><br />
<%= account_form.text_field :name %></div>
<% end %>
<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.submit "Sign up" %></div>
<% end %>
This is all the code I have. I haven't changed anything more.
And this is the error I got:
Account(#2175324980) expected, got ActiveSupport::HashWithIndifferentAccess(#2169631580)
Thanks in advance.
EDIT
I've found the solution:
I've changed
<%= f.fields_for :account do |account_form| %>
To
<%= f.fields_for :account_attributes, resource.account do |account_form| %>
Now I'm trying to add a :plan to account_form and I'm getting:
Can't mass-assign protected attributes: plan
EDIT 2
Ok, rookie mistake. I've just added :plan to account model.
After that I was getting an query error, I just changed some fields in my DB from null => false to null => true and voila.
I would expect it to look something like this. This involves subclassing devise's registrations controller
#models
class Account < ActiveRecord::Base
attr_accessible :name
has_many :users
end
class User < ActiveRecord::Base
belongs_to :account
accepts_nested_attributes_for :account
attr_accessible :first_name, :last_name, :account_attributes, :account, :email, :password, :password_confirmation, :remember_me
end
#app/controllers/registrations_controller.rb
class RegistrationsController < Devise::RegistrationsController
def new
#account = Account.new
super
end
end
#routes
devise_for :users, :controllers => {:registrations => "registrations"}
#view
<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name)) do |f| %>
<%= devise_error_messages! %>
<div><%= f.label :first_name %><br />
<%= f.text_field :first_name %></div>
<div><%= f.label :last_name %><br />
<%= f.text_field :last_name %></div>
<%= f.fields_for #account do |account_form| %>
<div><%= account_form.label :name %><br />
<%= account_form.text_field :name %></div>
<% end %>
<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.submit "Sign up" %></div>
<% end %>
Related
I am a newbie in Rails. I use Rails 4.2 with Ruby 2.0, I've installed the carrierwave gem. I followed the instructions how to setup with devise.
But the validation or the picture does not work correctly, cause I always get the "Avatar can't be blank" error message when I attached a picture and submit the form. I have no idea where is my mistake.
User model:
class User < ActiveRecord::Base
mount_uploader :avatar, AvatarUploader
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable,
:omniauthable, :omniauth_providers => [:facebook, :google_oauth2]
after_initialize :set_default_role, :if => :new_record?
# Validations
validates_presence_of :avatar
validates_integrity_of :avatar
validates_processing_of :avatar
def self.from_omniauth(auth)
where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
user.name = auth.info.nickname
user.email = auth.info.email
user.password = Devise.friendly_token[0,20]
end
end
end
Sign up form
<h2>Sign up</h2>
<%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: { multipart: true }) do |f| %>
<%= devise_error_messages! %>
<div class="field">
<%= f.label :name %><br />
<%= f.text_field :name, autofocus: true %>
</div>
<div class="field">
<%= f.label 'Woman' %><br />
<%= f.radio_button :gender, 'Woman' %>
<br>
<%= f.label 'Man' %><br />
<%= f.radio_button :gender, 'Man' %>
</div>
<div class="field">
<%= f.label :email %><br />
<%= f.email_field :email %>
</div>
<div class="field">
<%= f.label :phone %><br />
<%= f.text_field :phone %>
</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="field">
<%= f.label :city %><br />
<%= f.text_field :city %>
</div>
<div class="field">
<%= f.label :county %><br />
<%= f.text_field :county %>
</div>
<div class="field">
<label>My Avatar</label>
<%= f.file_field :avatar %>
<%= f.hidden_field :avatar_cache %>
</div>
<div class="actions">
<%= f.submit "Sign up" %>
</div>
<% end %>
<%= render "users/shared/links" %>
Application controller's strong parameters:
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_in) { |u| u.permit(:email) }
devise_parameter_sanitizer.for(:sign_up) { |u| u.permit({ roles: [] }, :name, :email, :password, :password_confirmation, :avatar, :avatar_cache) }
devise_parameter_sanitizer.for(:account_update) { |u| u.permit({ roles: [] }, :name, :email, :password, :password_confirmation, :avatar, :avatar_cache) }
end
I really do not see where is my mistake. Maybe do you see?
Because you have this validation:
validates_presence_of :avatar
means, you have to upload an avatar.
You will get this error message: Avatar can't be blank if you try to submit the form without attaching the avatar.
So, make sure you attach an avatar before hitting the Sign Up button.
While inserting some thing in firstName field its show error that firstName should not be blank....
Any Suggestion why this will be happening......?
Model
members.rb file
class Member < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
validates :firstName, :presence => true
end
View
new.html.erb file
<h2>Sign up</h2>
<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name)) do |f| %>
<%= devise_error_messages! %>
<div><%= f.label :firstName %><br />
<%= f.email_field :firstName, :autofocus => true %></div>
<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>
<div><%= f.submit "Sign up" %></div>
<% end %>
<%= render "devise/shared/links" %>
In Rails 4, you need to make a list of the parameters you are expecting a form to submit to you. this is called "strong parameters".
Devise has its own way that you can do this, called "sanitizing".
Look up those two terms.
See this answer: https://stackoverflow.com/a/20756469/2308190
Is it possible even you didn't input first name, but in params it still has value as empty string ""? If you use following, could it work?
validates :firstName, length: { minimum: 2 }
You can chage 2 to any other number.
Update your devise view with this.
<h2>Sign up</h2>
<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name)) do |f| %>
<%= devise_error_messages! %>
<div><%= f.label :firstName %><br />
<%= f.text_field :firstname, :autofocus => true %></div>
<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.submit "Sign up" %></div>
<% end %>
<%= render "devise/shared/links" %>
And model
validates :firstname, :presence => true
I have two models User and profile. The profile model has many attributes. I have accessed them in User model using accepts_nested_attributes_for.
Here is my profile.rb model
class Profile < ActiveRecord::Base
attr_accessible :address, :certification, :college, :contact_no, :first_name, :higher_education, :interested_in_learning, :last_name, :profile_pic, :school, :user_id, :would_like_to_teach, :about_video, :about_video_html, :category_name, :category_ids
mount_uploader :profile_pic, ProfimageUploader
has_and_belongs_to_many :categories
belongs_to :user
AutoHtml.add_filter(:image) do |text|
text.gsub(/http:\/\/.+\.(jpg|jpeg|bmp|gif|png)(\?\S+)?/i) do |match|
%|<img src="#{match}" alt=""/>|
end
end
auto_html_for :about_video do
image
youtube(:width => 170, :height => 100)
link :target => "_blank", :rel => "nofollow"
simple_format
end
def self.search(search)
if search
where('first_name LIKE ?', "%#{search}%")
else
find(:all)
end
end
end
Here is my user.rb model
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :token_authenticatable, :confirmable,
# :lockable, :timeoutable and :omniauthable
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :password, :password_confirmation, :remember_me
# Include default devise modules. Others available are:
# :token_authenticatable, :confirmable,
# :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable, :omniauthable
has_one :profile, :dependent => :destroy
accepts_nested_attributes_for :profile
# Setup accessible (or protected) attributes for your model
attr_accessible :name, :email, :password, :password_confirmation, :remember_me, :uid, :provider, :profile_attributes
mount_uploader :profile_pic, ProfimageUploader
acts_as_followable
acts_as_follower
def self.find_for_facebook_oauth(auth, signed_in_resource=nil)
user = User.where(:provider => auth.provider, :uid => auth.uid).first
if user
return user
else
registered_user = User.where(:email => auth.info.email).first
if registered_user
return registered_user
else
user = User.create(name:auth.extra.raw_info.name,
provider:auth.provider,
uid:auth.uid,
email:auth.info.email,
password:Devise.friendly_token[0,20],
)
end
end
end
end
The form in my User edit page is
<% resource.build_profile %>
<%= simple_form_for resource, :as => resource_name, :url => registration_path(resource_name), :html => { :method => :put, :multipart => true, :class => ".form-horizontal" } do |f| %>
<%= devise_error_messages! %>
<div><%= f.label :email %><br />
<%= f.email_field :email, :autofocus => true, :readonly => true %></div>
<% if devise_mapping.confirmable? && resource.pending_reconfirmation? %>
<div>Currently waiting confirmation for: <%= resource.unconfirmed_email %></div>
<% end %>
<div><%= f.label :password %> <i>(leave blank if you don't want to change it)</i><br />
<%= f.password_field :password, :autocomplete => "off" %></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>
<%= f.fields_for :profile, #user.profile do |prof| %>
<div class="field">
<%= prof.label :first_name %><br />
<%= prof.text_field :first_name %>
</div>
<div class="field">
<%= prof.label :last_name %><br />
<%= prof.text_field :last_name %>
</div>
<div class="field">
<%= prof.label :address %><br />
<%= prof.text_area :address %>
</div>
<div class="field">
<%= prof.label :profile_pic %><br />
<%= prof.file_field :profile_pic %>
</div>
<div class="field">
<%= prof.label :contact_no %><br />
<%= prof.text_field :contact_no %>
</div>
<div class="field">
<%= prof.label :school %><br />
<%= prof.text_field :school %>
</div>
<div class="field">
<%= prof.label :college %><br />
<%= prof.text_field :college %>
</div>
<div class="field">
<%= prof.label :higher_education %><br />
<%= prof.text_field :higher_education %>
</div>
<div class="field">
<%= prof.label :certification %><br />
<%= prof.text_field :certification %>
</div>
<div class="field">
<%= prof.label :about_video %><br />
<%= prof.text_field :about_video %>
</div>
<div class="field">
<%= prof.label :interested_in_learning %><br />
<%= prof.association :categories, :label => "Interested in learning", :wrapper_html => { :id => "iil_multiselect", :class=> "signup_field", :multiselect => true }%>
</div>
<!--<div class="field">
<%# prof.label :interested_in_learning %><br />
<%# prof.text_field :interested_in_learning %>
</div>-->
<div class="field">
<%= prof.label :would_like_to_teach %><br />
<%= prof.text_field :would_like_to_teach %>
</div>
<% end %>
<div><%= f.submit "Save" %></div>
<% end %>
<h3>Cancel my account</h3>
<p>Unhappy? <%= button_to "Cancel my account", registration_path(resource_name), :data => { :confirm => "Are you sure?" }, :method => :delete %></p>
My profile pic is not seen in the profile/show page What am i doing wrong?
I am trying to include nested attributes inside my Devise edit.html.erb file.
My models:
class User < ActiveRecord::Base
has_one :tutor, dependent: :destroy
accepts_nested_attributes_for :tutor, allow_destroy: true
devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable
end
and
class Tutor < ActiveRecord::Base
belongs_to :user
end
in my ApplicationController:
class ApplicationController < ActionController::Base
before_filter :configure_permitted_parameters, if: :devise_controller?
protect_from_forgery with: :exception
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:account_update) do |u|
u.permit(:first_name, :last_name, :email,
:is_tutor, :password,
# This is important for nested attributes
tutor_attributes: [:id, :_destroy, :user_id, :description]
:password_confirmation, :current_password)
end
end
end
And my view:
<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name), :html => { :multipart => true }) do |f| %>
<%= devise_error_messages! %>
<div><%= f.label :email %><br />
<%= f.email_field :email, :autofocus => true %></div>
<% if devise_mapping.confirmable? && resource.pending_reconfirmation? %>
<div>Currently waiting confirmation for: <%= resource.unconfirmed_email %></div>
<% end %>
<div><%= f.label :first_name %><br />
<%= f.text_field :first_name %></div>
<div><%= f.label :last_name %><br />
<%= f.text_field :last_name %></div>
<p>
<%= f.check_box :is_tutor %>
<%= f.label :is_tutor, 'Tutor' %>
</p>
<div>
<%= f.fields_for :tutor do |builder| %>
<fieldset>
<%= builder.label :description, 'Description' %><br />
<%= builder.text_area :description %><br />
<%= builder.check_box :_destroy %>
<%= builder.check_box :_destroy, 'Remove description' %>
</fieldset>
<% end %>
</div>
<br />
<div><%= f.label :password %> <i>(leave blank if you don't want to change it)</i><br />
<%= f.password_field :password, :autocomplete => "off" %></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>
<div><%= f.submit "Update" %></div>
<% end %>
When I go to the edit page, I do not see the fieldset with the nested attributes. The query to the db looks like this:
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = 1 ORDER BY "users"."id" A
SC LIMIT 1
Tutor Load (3.2ms) SELECT "tutors".* FROM "tutors" WHERE "tutors"."user_id" = ? ORDER BY "tuto
rs"."id" ASC LIMIT 1 [["user_id", 1]]
Any idea what I might be doing wrong?
Thanks!
This is probably due to the fact there is not a tutor association connected to the user. The fields would not show if the tutor was nil.
If so, you'll need to figure out how to do this on the user.
#user.build_tutor
Some options for adding this - You may need to overwrite the devise controller/method to add this. There may be some hooks provided by devise. You may do this in the view.
I have the following models defined in my application
User
Profile
Address
Here is my user model:
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :token_authenticatable, :encryptable, :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, :profile_attributes
has_one :profile
accepts_nested_attributes_for :profile
end
Here is my profile model:
class Profile < ActiveRecord::Base
attr_accessible :first_name, :last_name, :organization, :telephone_number, :user_id, :address_attributes
belongs_to :user
has_one :address
accepts_nested_attributes_for :address
end
Here is my address model:
class Address < ActiveRecord::Base
attr_accessible :street, :street_cont, :city, :state, :zip_code
belongs_to :profile
end
I am using devise for authentication so in my view I have the following for registration:
<% resource.build_profile %>
<h2>Sign up</h2>
<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name)) do |f| %>
<%= devise_error_messages! %>
<p><%= f.label :email %><br />
<%= f.email_field :email %></p>
<p><%= f.label :password %><br />
<%= f.password_field :password %></p>
<p><%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation %></p>
<%=f.fields_for :profile do |profile_form| %>
<p><%= profile_form.label :first_name %><br />
<%= profile_form.text_field :first_name %></p>
<p><%= profile_form.label :last_name %><br />
<%= profile_form.text_field :last_name %></p>
<p><%= profile_form.label :organization %><br />
<%= profile_form.text_field :organization %></p>
<p><%= profile_form.label :telephone_number %><br />
<%= profile_form.text_field :telephone_number %></p>
<%=f.fields_for :address do |address_form| %>
<p><%= address_form.label :street %><br />
<%= address_form.text_field :street %></p>
<p><%= address_form.label :street_cont %><br />
<%= address_form.text_field :street_cont %></p>
<p><%= address_form.label :city %><br />
<%= address_form.text_field :city %></p>
<p><%= address_form.label :state %><br />
<%= address_form.text_field :state %></p>
<p><%= address_form.label :zip_code %><br />
<%= address_form.text_field :zip_code %></p>
<% end %>
<% end %>
<p><%= f.submit "Sign up" %></p>
<% end %>
<%= render :partial => "devise/shared/links" %>
The form renders correctly but when I view the source I see this for the address fields:
<input id="user_address_street" name="user[address][street]" size="30" type="text" />
for the profile section I see:
<input id="user_profile_attributes_first_name" name="user[profile_attributes][first_name]" size="30" type="text" />
When I save the form, the user and profile are saved to the database but not the address. I'm obviously doing something wrong possibly with my model relationships but I don't know how to go about solving this.
Any help would be appreciated.
Change this:
<%=f.fields_for :address do |address_form| %>
To this:
<%=profile_form.fields_for :address do |address_form| %>