Devise, create a user that belongs to company - ruby-on-rails

I want to create a user with Devise, that have a belongs_to association.
What is missing? What needs to create a user that belongs to a company from a select list?
my form have this:
.siimple-form-field
= f.label :name, class: "siimple-label"
br
= f.text_field :name, autofocus: true, autocomplete: "email", class: "siimple-input siimple-input--fluid siimple--height-50"
.siimple-form-field
label.siimple-label
| Select an option:
= f.fields_for :company_attributes do |b|
= b.select :company, Company.all.collect{|p| [p.name, p]}, {}, class: "siimple-select siimple-select--fluid"
the form shows ok, so when i try to submit, it says:
1 error prohibited this user from being saved:
Company must exist
Also my RegistrationsController have:
def create
super
end
def configure_sign_up_params
devise_parameter_sanitizer.permit(:sign_up, keys: [:name, :bank])
end

Solved!
First them all, the registration controller was not overriden in the routes files, just got this:
devise_for :users, controllers: {
sessions: 'users/sessions',
# something missing no?
}
Fixed it with
devise_for :users, controllers: {
sessions: 'users/sessions',
registrations: 'users/registrations'
}
Then, just do common things like add something like this to the controller:
def create
params[:user][:company] = Company.find(params[:user][:company_id])
super
end
And add the missing permission to configure_sign_up_params
def configure_sign_up_params
devise_parameter_sanitizer.permit(:sign_up, keys: [:name, :company_id, :company])
end

I think your problem here is that the company parameters are not being permitted (which means the company gets set to nil, hence the Company must exist error).
You have to override Devise's resource_params method to add your company_id attribute. Try putting this in your Registrations controller:
def resource_params
params.require(:user).permit(:user_attribute_foo, :user_attribute_bar, :company_id)
end

I think your column name is company_id and you are using company in the form. Try by changing it and permit this parameter.

Related

Rails - How to add additional column value into Devise registration table?

User Model
class User < ApplicationRecord
belongs_to :tenant, dependent: :destroy
end
Tenant Model
class Tenant < ApplicationRecord
has_many :users
end
Controller
Workaround 1 (not working)
def create
super
#tenant = Tenant.new
#user = #tenant.build_user(params)
#tenant.save
end
Workaround 2 (not working)
def create
#tenant = Tenant.new
#user = User.build(params)
#tenant.save
super
end
Is there any possibilities to pass a parameter to devise super class?
Since Devise super method has its own functionality on user registration/password hashing/, I can not completely override the function.
I know the way I am saving is wrong, please suggest me the better approach.
Actual source code:
(with Controller, Model, Migrations and Routes files are added.)
https://repl.it/#aravin/HarmlessRepentantHarddrive
You can override the sign_up_params in your controller:
class RegistrationsController < Devise::RegistrationsController
private
def sign_up_params
params.require(:user).permit(:first_name, :last_name, :email, :password, :password_confirmation...).merge({tenant_id: Tenant.create!.id})
end
end
I wanted to provide a little more verbose answer than was provided by AbM.
You can generate the registrations_controller.rb file with the following command:
rails g devise:controllers users -c=registrations
Once you do this, you will want to modify it such that you have something like:
class RegistrationsController < Devise::RegistrationsController
private
def sign_up_params
params.require(:user).permit(:first_name, :last_name, :email, :password, :password_confirmation)
end
def account_update_params
params.require(:user).permit(:first_name, :last_name, :email, :password, :password_confirmation, :current_password)
end
end
Then in your routes.rb file you will want to change the devise_for line to tell devise that you want to override your registrations controller like:
devise_for :users, controllers: { registrations: 'users/registrations' }
Of course, you will want to replace the :user/:users references to the name of your devise authentication model if you are using something other than the standard User throughout my example.
Here is a reference to this in the official docs on GitHub.

Rails 4 and Devise - routing issue with sign-up page

I have a routing question related to Devise.
I have model - Member (rather than User) and I have some custom routes
devise_for :members, controllers: {registrations 'members/registrations',
omniauth_callbacks: 'members/omniauth_callbacks',
sessions: 'members/sessions' }
devise_scope :member do
authenticated :member do
root :to => 'home#index', as: :authenticated_root
end
unauthenticated :member do
root :to => 'devise/sessions#new', as: :unauthenticated_root
end
end
My issue relates to my sign-up page when it fails (due to a validation failing).
The displayed URL is
http://localhost:3000/members/sign_up
But if validation fails it redirects to
http://localhost:3000/members
(this page does show the registration/new form and this form works fine if the input validates)
In contrast, on my sign-in page
http://localhost:3000/members/sign_in
if failing validation redirects back to itself
http://localhost:3000/members/sign_in
Now you may wonder why I am asking this. I have an implementation of growly flash messages to indicate validation failure. They work on all the different devise views except the sign-up one. This routing difference is the only difference I can see between them. I am guessing that if the sign-up page redirected to itself on failure, like the sign-in page then the flash messages will work.
Its an odd question but some insights on this routing/URL behaviour in devise would be really helpful.
Registrations_controller.rb
class Members::RegistrationsController < Devise::RegistrationsController
# GET /resource/sign_up
def new
build_resource({})
self.resource.user = User.new
respond_with self.resource
end
# POST /resource
def create
super
resource.user.ip_address = request.remote_ip
unless resource.email.nil? || resource.email.empty?
resource.user.email = resource.email
resource.user.save
end
end
private
def sign_up_params
allow = [:provider, :uid, :email, :password, :password_confirmation, user_attributes: [:member_id, :email, :first_name, :last_name, :institution, :city, :country, :job_title, :about, :tag_list, :picture, :ip_address]]
params.require(resource_name).permit(allow)
end
end

Devise - Insert data into HAS_ONE related model during sign up

I have a User model, that has_one Profile.
Profile is the place where all the user stuff is saved (name, phone, address, state, etc).
During sign up I need to let user fill in those fields.
Tried to do nested fields but it doesn't really work and I don't really understand why.
Does anyone have similar code examples? Can't find anything in Internet.
Candidate has_one :profile
Profile belongs_to :user
Registration form:
= simple_form_for(:candidate,
as: Candidate,
url: candidate_registration_path) do |f|
= f.simple_fields_for :profile do |profile|
= profile.input :first_name
= profile.input :last_name
= f.input :email
= f.input :password
= f.input :password_confirmation
= f.submit 'Start Building', class: 'btn btn-primary'
Didn't do anything with controllers except this:
def configure_devise_params
devise_parameter_sanitizer.for(:sign_up) do |u|
u.permit(:email, :password, :password_confirmation,
profile_attributes: [:first_name, :last_name])
end
end
When you say it doesn't work do you mean that it doesn't save? Or it doesn't show the fields?
In the latter case, you would have to build the blank profile in the registrations controller before the action is hit. So basically override the devise controller and do something like this:
class RegistrationsController < Devise::RegistrationsController
def new
user = build_resource({})
user.build_profile if user.profile.blank?
respond_with self.resource
end
end
routes.rb
devise_for :candidates, :controllers => {:registrations => "registrations"}
Candidate.rb
has_one :profile
accepts_nested_attributes_for :profile
and make sure the code you have written above for strong parameters is in your application_controller.
This is also assuming your devise model is called "Candidate"
Check the params in your log. Try creating a user in console using those params. Do you have accepts_nested_attributes_for :profile on your user model?

Strong parameters - Devise 3.0.0 and Rails 4. "Unpermitted parameters: name"

I am currently using Rails 4 and Devise 3.0.0. I have tried to add a custom field of "Name" to the sign up form and edit registration form. Whenever I submit the form, the following errors arise:
Unpermitted parameters: name
WARNING: Can't mass-assign protected attributes for User: email, password, password_confirmation.
I understand that this has something to do with the way Rails 4 handles parameters, but I do not understand what I am supposed to do about it right now. I have searched around and have seen that I am supposed to add some lines to a User model involving "params."
My user model currently looks like this:
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable, #:recoverable,
:rememberable, :trackable, :validatable
attr_accessible :name, :password, :password_confirmation, :remember_me, :email
end
According to How is attr_accessible used in Rails 4?, I am supposed to add the following code to "The controller."
class PeopleController < ApplicationController
def create
Person.create(person_params)
end
private
def person_params
params.require(:person).permit(:name, :age)
end
end
What controller? And is this literal code? Since I am dealing with User, do I have to use User.create(user_params)? instead of Person.create(person_params)?
Rails 4 has moved parameter sanitisation to the Controller from the Model. Devise handles it for 3 actions, sign_in, sign_up and account_update. For sign_up, the permitted parameters are authentication key (which is :email by default), password and password_confirmation.
If you want to add :name to the User model and use it for sign_up, either change config.authentication_keys = [ :email ] to config.authentication_keys = [ :name ] in /config/initializers/devise.rb or, if you want to use both :email and :name, add this to the ApplicationController
class ApplicationController < ActionController::Base
before_action :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) << :username
end
end
Also check-
https://github.com/plataformatec/devise#strong-parameters
You have to add this in controller where you have written User.create(user_params). I am assuming that UsersController.
class UsersController < ApplicationController
def create
User.create(user_params)
end
private
def user_params
#assumption: user params are coming in params[:user]
params.require(:user).permit(:name, :age, :and_other_params_you_want_to_allow)
end
end
Yes, you should add one line which is like:-
attr_accessible :name
in your model to allow name to assigned and if it does not work try this How is attr_accessible used in Rails 4?
I have similar problem. So, to fix it I created custom registration controller inherit form DeviseRegistration controller. Check Devise documentation and define controller like this.
class RegistrationsController < Devise::RegistrationsController
before_filter :update_sanitized_params, if: :devise_controller?
def update_sanitized_params
devise_parameter_sanitizer.for(:sign_up) {|u| u.permit(:name, :email, :)}
end
end
Make sure you have define this routes for this controller in config/routes.rb
devise_for :users, :controllers => {:registrations => "registrations" } , :path => '', :path_names => {
:sign_in => 'login',
:sign_out => 'logout'
}
Check this documentation of devise for strong parameter.
i had similar issues, this was my fix:
class ApplicationController < ActionController::Base
before_filter :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:account_update) { |u| u.permit!}
end
end

devise and multiple "user" models

I'm using rails 3.2 and devise 2.0 and I'm quite new to Rails.
Requirements
I'd like to achieve the following:
have 2 or more "user" models, eg. Member, Customer, Admin
all models share some required fields (eg. email and password)
each model may have some unique fields (eg. company for Customer only)
some fields may be shared but not have the same validation (eg. name is required for Customer but optional for Member)
all fields must be filled during the registration process, so the forms are different
the login form should be unique
Possible solutions
I googled and searched StackOverflow for quite a long time, but nothing seems right to me (I'm a Java guy, sorry :) and now I'm quite confused. Two solutions came up:
Single devise user
That's the most frequent answer. Just create the default devise User and create relations between Member-->User and Customer-->User.
My concern here is how can I achieve a customized registration process for each model? I tried different things but all ended as a mess!
Multiple devise users
This solves the custom registration process, and seems right to me, but the unique login form is a blocker. I found an answer on SO (Devise - login from two model) which suggests to override Devise::Models::Authenticatable.find_for_authentication(conditions).
That seems complicated (?) and since I'm new to rails, I'd like to know if that could work?
Thanks for your advice!
Welcome aboard Java guy =), I hope you'll enjoy the Rails world.
Simply, to solve your issue you have 2 solutions:
For each user create a table in the database and corresponding model.
Create a single table in the database and for each user type create a model. This is called single table inheritance (STI).
Which one to choose?
It depends on the common attributes of the roles. If they are almost common (for example all have a name, email, mobile, ...) and a few attributes are different, I highly recommend the STI solution.
How to do the STI?
1. Simply create the the devise user model and table using the command rails generate devise User
2. Add a column named type with string datatype to the user table in the database using a migration.
3. For each user type create a model (for example rails g model admin)
4. Make the Admin class inherits from user model
class Admin < User
end
That's it you are done =) ... Yupeee
To create an admin run the command Admin.create(...) where the dots is the admin attributes for example the email, name, ...
I think this question could help you too
I'm in similar shoes as you, after trying all sorts of approaches I went with a single User model, which would belong to polymorphic roles. This seems like the simplest way to achieve single-login.
The User model would contain the information specific to log-in only.
The Role model would store fields specific to each role, as well as other associations specific to the role.
New registrations would be customized for each user type (roles) via individual controllers, and then building nested attributes for the User.
class User < ActiveRecord::Base
#... devise code ...
belongs_to :role, :polymorphic => true
end
class Member < ActiveRecord::Base
attr_accessible :name, :tel, :city #etc etc....
attr_accessible :user_attributes #this is needed for nested attributes assignment
#model specific associations like
has_many :resumes
has_one :user, :as => :role, dependent: :destroy
accepts_nested_attributes_for :user
end
Routes -- just regular stuff for the Member model.
resources :members
#maybe make a new path for New signups, but for now its new_member_path
Controller -- you have to build_user for nested attributes
#controllers/members_controller.rb
def new
#member = Member.new
#member.build_user
end
def create
#... standard controller stuff
end
views/members/new.html.erb
<h2>Sign up for new members!</h2>
<%= simple_form_for #member do |f| %>
# user fields
<%= f.fields_for :user do |u| %>
<%= u.input :email, :required => true, :autofocus => true %>
<%= u.input :password, :required => true %>
<%= u.input :password_confirmation, :required => true %>
<% end %>
# member fields
<%= f.input :name %>
<%= f.input :tel %>
<%= f.input :city %>
<%= f.button :submit, "Sign up" %>
<% end %>
I would like to point out that there is NO NEED to reach for nested_form gem; since the requirement is that User can only belong_to one type of Role.
I found a way to go and I'm quite happy with it so far. I'll describe it here for others.
I went with the single "user" class. My problem was to achieve a customized registration process for each pseudo model.
model/user.rb:
class User < ActiveRecord::Base
devise :confirmable,
:database_authenticatable,
:lockable,
:recoverable,
:registerable,
:rememberable,
:timeoutable,
:trackable,
:validatable
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :password, :password_confirmation, :remember_me, :role
as_enum :role, [:administrator, :client, :member]
validates_as_enum :role
## Rails 4+ for the above two lines
# enum role: [:administrator, :client, :member]
end
Then I adapted http://railscasts.com/episodes/217-multistep-forms and http://pastie.org/1084054 to have two registration paths with an overridden controller:
config/routes.rb:
get 'users/sign_up' => 'users/registrations#new', :as => 'new_user_registration'
get 'clients/sign_up' => 'users/registrations#new_client', :as => 'new_client_registration'
post 'clients/sign_up' => 'users/registrations#create', :as => 'client_registration'
get 'members/sign_up' => 'users/registrations#new_member', :as => 'new_member_registration'
post 'members/sign_up' => 'users/registrations#create', :as => 'member_registration'
controllers/users/registrations_controller.rb:
I created a wizard class which knows the fields to validate at each step
class Users::RegistrationsController < Devise::RegistrationsController
# GET /resource/sign_up
def new
session[:user] ||= { }
#user = build_resource(session[:user])
#wizard = ClientRegistrationWizard.new(current_step)
respond_with #user
end
# GET /clients/sign_up
def new_client
session[:user] ||= { }
session[:user]['role'] = :client
#user = build_resource(session[:user])
#wizard = ClientRegistrationWizard.new(current_step)
render 'new_client'
end
# GET /members/sign_up
def new_member
# same
end
# POST /clients/sign_up
# POST /members/sign_up
def create
session[:user].deep_merge!(params[:user]) if params[:user]
#user = build_resource(session[:user])
#wizard = ClientRegistrationWizard.new(current_step)
if params[:previous_button]
#wizard.previous
elsif #user.valid?(#wizard)
if #wizard.last_step?
#user.save if #user.valid?
else
#wizard.next
end
end
session[:registration_current_step] = #wizard.current_step
if #user.new_record?
clean_up_passwords #user
render 'new_client'
else
#session[:registration_current_step] = nil
session[:user_params] = nil
if #user.active_for_authentication?
set_flash_message :notice, :signed_up if is_navigational_format?
sign_in(:user, #user)
respond_with #user, :location => after_sign_up_path_for(#user)
else
set_flash_message :notice, :"signed_up_but_#{#user.inactive_message}" if is_navigational_format?
expire_session_data_after_sign_in!
respond_with #user, :location => after_inactive_sign_up_path_for(#user)
end
end
end
private
def current_step
if params[:wizard] && params[:wizard][:current_step]
return params[:wizard][:current_step]
end
return session[:registration_current_step]
end
end
and my views are:
new.rb
new_client.rb including a partial according to the wizard step:
_new_client_1.rb
_new_client_2.rb
new_member.rb including a partial according to the wizard step:
_new_member_1.rb
_new_member_2.rb
So what's wrong? Just run rails g devise:views [model_name], customize each registration forms and in config/initializer/devise.rb just put config.scoped_views = true.

Resources