Multiselect with Devise and simple_form - ruby-on-rails

I have a rails application that uses Devise and simple_form to register and authenticate a user. I wanted to add another table of preferences such that a user can have multiple preferences and a preference can be assigned to multiple users.
I followed this: https://dev.to/neshaz/join-table-in-rails-23b5
and made the respective associations with a join table and I am able to view the checkboxes multiselect on my form. But I am stuck on the part on processing the params in my registration controller page. For context this is what i have:
registration_controller.rb
def configure_sign_up_params
devise_parameter_sanitizer.permit(:sign_up) do |u|
u.permit({ account_attributes: [:username], invite_request_attributes: [:text] }, :company, :email, :password, :password_confirmation, :invite_code, :agreement, :website, :confirm_password)
end
end
_registration.html.haml:
- for preference in Preference.all
= check_box_tag "preference[user_ids][]", preference.id
= h preference.pref

You try this way.
class ApplicationController < ActionController::Base
before_action :configure_permitted_parameters, if: :devise_controller?
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_up, keys: [:name, preference_ids: []])
devise_parameter_sanitizer.permit(:account_update, keys: [:name, :website, :bio])
end
end
_registration.html.haml:
- for preference in Preference.all
= check_box_tag "user[preference_ids][]", preference.id
= h preference.pref

Related

Unable to permit additional parameters in devise#accept invitation

I'm unable to permit additional parameters in invite#accept. I've setup everything and here's a controller.
But in the method accept_resource there're still only 3 old parameters accepted, other didn't come through, although they present on a form.
class MyInvitationsController < Devise::InvitationsController
before_filter :configure_permitted_parameters, if: :devise_controller?
before_filter :update_sanitized_params, only: [:edit, :update]
def edit
puts "edit...."
super
end
private
def accept_resource
puts "accept_resource..."
resource = resource_class.accept_invitation!(update_resource_params)
# but it still permits only :password, :password_confirmation and :invitation_token
resource
end
protected
def configure_permitted_parameters
puts "configure_permitted_parameters..."
devise_parameter_sanitizer.permit(:sign_up, keys: [:aaa, :bbb, :ccc, :password, :password_confirmation,
:invitation_token])
end
def update_sanitized_params
puts "update_sanitized_params..."
devise_parameter_sanitizer.permit(:sign_up, keys: [:aaa, :bbb, :ccc, :password, :password_confirmation,
:invitation_token])
How to fix that?
I use devise 4.2 and devise_invitable 1.6
Try remove
if: :devise_controller?
in your before_filter, because your are not in devise controller.

Saving other attributes to User model with Devise gem

I have created a User model through the Devise gem that allows email, first_name, and password upon registration.
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) << :first_name
end
I would like to save other attributes such as last_name, city, etc to the User model. I have ran the migrations and see these attributes in my schema.
However when I am on the user/edit page and try to save, the new attributes are not saving.
I have run the command to edit the devise controllers, but confused.
rails generate devise:controllers users
Do I still need to create a UsersController < ApplicationController in order to accept other attributes into the User model during an edit/update?
Then I could just permit all when trying to update
def user_params
params.require(:user).permit!
end
Thanks
Try this:
class ApplicationController < ActionController::Base
protect_from_forgery
before_filter :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:user) << :first_name
end
end
Add the following filter to the application controller:
before_action :configure_permitted_parameters, if: :devise_controller?
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) { |u| u.permit( :first_name, :email, :password, :password_confirmation) }
end
This is for sign up. To update the user informaiton add following line of code within the configure_permitted_parameters filter.
devise_parameter_sanitizer.for(:account_update) { |u| u.permit(:first_name, :email, :password, :password_confirmation, :current_password) }

Devise: change params in registrations controller

I want to change parameter before it saves in model object in create action of Devise registrations_controller
class RegistrationsController < Devise::RegistrationsController
before_filter :configure_permitted_parameters
def create
phone = params[:user][:phone]
replacements = [ [' ', ''], ['-', ''], ['(', ''], [')', ''], ['+', ''] ]
params[:user][:phone] = replacements.each { |replacement| phone.gsub!(replacement[0], replacement[1]) }
super
end
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) do |u|
u.permit(:name, :surname, :patronymic, :username, :phone, :email, :password, :password_confirmation)
end
devise_parameter_sanitizer.for(:account_update) do |u|
u.permit(:name, :surname, :patronymic, :username, :phone, :email, :password, :password_confirmation, :current_password)
end
end
end
The problem is I can't change params[:user][:phone] because it unpermitted: Unpermitted parameters: phone. How can I change it after I get params? Thanks!
These aren't permitted because of Rails Strong Parameters. See the 'Strong Parameters' section in the Devise Github page.
Long story short, something like this should be placed into your ApplicationController, not the Devise controllers:
class ApplicationController < ActionController::Base
before_action :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) << :phone
end
end

Custom user fields in Devise 3 under Rails 4

I'm using the release candidate of Devise 3 so that I can use it with Rails 4. In Rails 3.2 I used to be able to add a custom field to my User model by simply adding that field to the registration/edit.html.erb and registration/new.html.erb files (after running the proper migration). Then I'd just add that field to the attr_accessible list of fields in the model.
However, in Rails 4, there is no attr_accessible list and I can't simply add fields in the views. How do I add custom User fields?
Adding
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_in) { |u| u.permit(:username, :email) }
devise_parameter_sanitizer.for(:sign_up) { |u| u.permit(:username, :email, :password, :password_confirmation) }
devise_parameter_sanitizer.for(:account_update) { |u| u.permit(:username, :email, :password, :password_confirmation, :current_password) }
end
To applicationcontroller worked for me.
I was told to look in the main README on the github page and there it was. Easy.
class ApplicationController < ActionController::Base
before_filter :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) << :username
end
end
In case you want to permit additional parameters you can do with a simple before filter in your
ApplicationController:
class ApplicationController < ActionController::Base
before_filter :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) << :username
end
end
You need to enable Strong Parameters for devise instead of attr_accessible for doing that you need to create new initializer like:
DeviseController.class_eval do
def resource_params
unless params[resource_name].blank?
params.require(resource_name).permit(:email, :password, :password_confirmation, :remember_me)
end
end
end
Make sure that you cloned gem from rails4 branch(plataformatec/devise).
Remove attr_accesible from model

Adding extra registration fields with Devise

I am trying to add some extra fields to registrations#new. Since I only want extra data and do not need different functionality, I don't see why I need to override controllers etc. So what I did was modify registrations#new as follows:
%h2
Sign up
= 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
= f.label :title_id
%br
= f.text_field :title_id
%div
= f.label :province_id
%br
= f.text_field :province_id
%div
= f.label :first_name
%br
= f.text_field :first_name
%div
= f.label :last_name
%br
= f.text_field :last_name
%div
= f.label :password
%br
= f.password_field :password
%div
= f.label :password_confirmation
%br
= f.password_field :password_confirmation
%div= f.submit 'Sign up'
= render 'devise/shared/links'
To enable these extra fields through the sanitizer, I updated ApplicationController as follows:
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
before_filter :store_requested_url!
# before_filter :authenticate_user!
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_in) { |u| u.permit(:email) }
devise_parameter_sanitizer.for(:sign_up) { |u| u.permit(:email, :password, :password_confirmation, :title_id, :province_id, :first_name, :last_name) }
devise_parameter_sanitizer.for(:account_update) { |u| u.permit(:email, :password, :password_confirmation, :current_password) }
end
def after_sign_in_path_for(resource)
session[:requested_url] || root_path
end
private
def store_requested_url
# store last url as long as it isn't a /users path
session[:previous_url] = request.fullpath unless request.fullpath == /\/users/
end
end
For some reason, it is not working and the extra fields go to the database as nulls.
I am using Ruby 2 and Rails 4 rc1, with Devise 3.0.0.rc.
It would appear that the code sample in your question is not working because you are not setting the before_filter to call the sanitizer.
before_filter :configure_permitted_parameters, if: :devise_controller?
With that said, it's probably better to override the controller, as shown in the accepted answer, so that the application controller isn't doing this check all of the time. The accepted answer can be shortened up with the code below. I've tested this code with my application and it works well. All of this is documented in the Strong Parameters section of the README in the 3.0.0.rc tag.
Override the controller:
class RegistrationsController < Devise::RegistrationsController
before_filter :configure_permitted_parameters, :only => [:create]
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) { |u| u.permit(:username, :email, :password) }
end
end
Then update the routes to use it:
devise_for :members, :controllers => { :registrations => "registrations" }
As of Devise version 4.3.0, May 15th 2017, the solution is as follows from the documentation. In this case, the username field is being added.
In case you want to permit additional parameters (the lazy way™), you can do so using a simple before filter in your ApplicationController:
class ApplicationController < ActionController::Base
before_action :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_up, keys: [:username])
end
end
And of course, simply add the field to your database
> rails g migration AddUsernameToUsers
class AddUsernameToUsers < ActiveRecord::Migration[5.0]
def change
add_column :users, :username, :string, null: false, index: true, unique: true
end
end
And then add the necessary fields into the view for registrations#new
<%= f.text_field :username, placeholder: "Username" %>
After Devise 4.0 the older answers on this topic are not valid. instead of the for method you have to use:
devise_parameter_sanitizer.permit(:sign_up, keys: [:username])
So, for a complete solution in ApplicationController:
class ApplicationController < ActionController::Base
before_action :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_up, keys: [:username])
end
end
OK, so what I did was just override the Devise registration controller, update routes.rb as per the devise docs to reflect this, copied and pasted the Devise code for registrations#create as is, and change the getting params part to use my own strong parameters method, and that was that.
class RegistrationsController < Devise::RegistrationsController
def create
build_resource(registration_params)
if resource.save
if resource.active_for_authentication?
set_flash_message :notice, :signed_up if is_navigational_format?
sign_up(resource_name, resource)
respond_with resource, :location => after_sign_up_path_for(resource)
else
set_flash_message :notice, :"signed_up_but_#{resource.inactive_message}" if is_navigational_format?
respond_with resource, :location => after_sign_up_path_for(resource)
end
else
clean_up_passwords
respond_with resource
end
end
private
def registration_params
params.require(:user).permit(:email, :title_id, :first_name, :last_name,
:province_id, :password, :password_confirmation)
end
end
First expose the views
rails generate devise:views users
then edit config/initializers/devise.rb and change
# config.scoped_views = false
to
config.scoped_views = true
this will allow you to modify the views at app/views/users/registration.
you will add the fields needed here, in both
app/views/users/registration/edit.html.erb
app/views/users/registration/new.html.erb
Now we have to deal with rails mass assignment issue, go to application_controller.rb and add a before_filter
before_filter :configure_permitted_parameters, if: :devise_controller?
then add your fields + original fields to devise sanitization
protected
def configure_permitted_parameters
# Fields for sign up
devise_parameter_sanitizer.for(:sign_up) { |u| u.permit(:username, :email, :password) }
# Fields for editing an existing account
devise_parameter_sanitizer.for(:account_update) { |u| u.permit(:username, :email, :password, :current_password, :gender) }
end
restart your web server and cross your fingers.
I've had similar situation (just fields were different).
Here's the way official documentation can offer:
Just add this to your ApplicationController. And change "username" to whatever you need, and add some more if you need.
before_action :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) << :username
end
My Applications Controller looks like that:
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
before_action :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) << :public_name
end
end
More details here: https://github.com/plataformatec/devise ("Strong Parameters")
First: Isn't there a new 'strong parameters' issue with rails 4, you might want to look into this as well.
If you migrate the new parameters into your User model. Then all you have to do is to override (create) the files:
app/views/devise/registrations/edit.html.erb
app/views/devise/registrations/new.html.erb
you can look at the default files here:
https://github.com/plataformatec/devise/tree/master/app/views/devise/registrations
IF you might want to implement an own registrations_controller.rb (with actions new and edit) and your own #variables then it is important to add this in your routes.rb
devise_for :users, :controllers => { :registrations => 'registrations' }
resources :users
This ensures, that devise takes your new 'registrations' controller from now on (if you decided to have one).
I don't know "sanitizer" or what this is good for. But my App works just fine with those minor changes I just recommended to you. You don't need to override the Controller! Overriding the Views will just be enough.
New fields could be added like this example. For Devise 4, the Parameter Sanitaizer API has changed:
class ApplicationController < ActionController::Base
before_action :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_up, keys: [:username, :name])
end
end

Resources