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| %>
Related
I'm attempting to add a nested form into the Devise registration form.
My 3 tables are Users (devise), Languages, and they both are joined in Languages_Users
It signs up the new user, but does not save Languages_Users, but I see that it is passed in the params. A new issue has also arisen - the avatar file is no longer saved. I'm not sure if these are related (if not, don't worry about addressing it).
**UPDATE - Here are my current logs - I now think the issue due to languages_users not receiving user_id
"languages users can't be blank'. In my logs though, it says 'SELECT 1 AS one FROM "languages_users" WHERE ("languages_users"."user_id" IS NULL AND "languages_users"."language_id" = 2) LIMIT 1' Is this an issue with not passing the user_id?
**
User.rb
class User < ActiveRecord::Base
has_many :languages_users
has_many :languages, :through => :languages_users
accepts_nested_attributes_for :languages_users
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
belongs_to :role
has_attached_file :avatar, :styles => { :medium => "300x300>", :thumb => "100x100#" }, :default_url => "/images/:style/missing.png"
validates_attachment_content_type :avatar, :content_type => /\Aimage\/.*\Z/
validates_presence_of :first_name, :last_name, :location, :nationality, :bio
end
registrations_controller.rb
class Users::RegistrationsController < Devise::RegistrationsController
before_filter :configure_permitted_parameters
def new
build_resource({})
resource.languages_users.build
respond_with self.resource
end
def create
super
end
private
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) { |u|
u.permit(:email, :password, :password_confirmation, :bio, :location, :last_name, :first_name, :nationality, :avatar, languages_user_attributes: [:id, :language_id, :user_id, :level]) }
end
end
in registrations:
new.html.erb
<h2>Sign up</h2>
<%= form_for(resource, as: resource, url: registration_path(resource)) do |f| %>
<%= devise_error_messages! %>
<div class="field">
<%= f.label :first_name %><br />
<%= f.text_field :first_name, autofocus: true %>
</div>
<div class="field">
<%= f.label :last_name %><br />
<%= f.text_field :last_name %>
</div>
<div class="field">
<%= f.label :location %><br />
<%= f.text_field :location %>
</div>
<div class="field">
<%= f.label :nationality %><br/>
<%= f.text_field :nationality %>
</div>
<div class="field">
<%= f.label :bio %><br />
<%= f.text_field :bio %>
</div>
<div class="field">
<%= f.label :email %><br />
<%= f.text_field :email %>
</div>
<div class="form-group">
<%= f.label :avatar, class: 'col-sm-2 control-label' %>
<div class="col-sm-6">
<%= f.file_field "user[avatar]" %>
</div>
</div>
<%= f.fields_for :langauges_user do |lu| %>
<br>
<div class="fields">
<%= lu.collection_select(:language_id, Language.order('language ASC').all, :id, :language) %><br>
<%= lu.hidden_field :level, value: 1 %>
<% end %>
</div>
<br>
<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 %>
logs:
Started POST "/users" for ::1 at 2016-03-26 13:30:40 -0400
Processing by Users::RegistrationsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"x1F0kXqKN2/uu7S6BLxyBgSatcVWiSOLASEYYJ7ZF0b3d8V8O+FVQAO0yhjTJ2LImI+Xy4j7Rn+SvlYjV07mrA==", "user"=>{"first_name"=>"John", "last_name"=>"Smith", "location"=>"NYC", "nationality"=>"American", "bio"=>"hello", "email"=>"johns#gmail.com", "user"=>{"avatar"=>#<ActionDispatch::Http::UploadedFile:0x007f940b16a4f8 #tempfile=#<Tempfile:/var/folders/cn/l75pvjk9707bj93z_yykb0t40000gn/T/RackMultipart20160326-11607-1fg5ncg.JPG>, #original_filename="IMG_4573.JPG", #content_type="image/jpeg", #headers="Content-Disposition: form-data; name=\"user[user[avatar]]\"; filename=\"IMG_4573.JPG\"\r\nContent-Type: image/jpeg\r\n">}, "langauges_users"=>{"language_id"=>"16", "level"=>"1"}, "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"}, "commit"=>"Sign up"}
Unpermitted parameters: user, langauges_users
Still a newb, so please let me know if you'd like me to provide anything further.
Thanks!
You should change languages_user to languages_users
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) { |u|
u.permit(:email, :password, :password_confirmation, :bio, :location, :last_name, :first_name, :nationality, :avatar, languages_users_attributes: [:id, :language_id, :user_id, :level]) }
end
Also in fields_for
<%= f.fields_for :languages_users do |lu| %>
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.
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'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 %>