My rails app has a few cab operators and they have a few cabs, and they are related as follows:
class Operator < ActiveRecord::Base
has_many :cabs
end
I wish to add authentication system so as to create admins for each operator. I am using Devise. Since I need to create path as: operator/:operator_id/admins/sign_up, I generated the Admin model, as:
rails generate devise Admin
Then I modified my routes so as to obtain the above mentioned path:
scope "operators/:operator_id" do
devise_for :admins
end
Running rake routes shows that I am getting the required urls. I also modified the models:
class Admin < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
belongs_to :operator
end
class Operator < ActiveRecord::Base
has_many :admins
end
I also modified the devise/sessions/new.html.irb to include a hidden field for operator_id:
h2>Log in
<%= form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %>
<div><%= f.label :email %><br />
<%= f.email_field :email, autofocus: true %></div>
<div><%= f.label :password %><br />
<%= f.password_field :password, autocomplete: "off" %></div>
<% if devise_mapping.rememberable? -%>
<div><%= f.check_box :remember_me %> <%= f.label :remember_me %></div>
<% end -%>
<% f.hidden_field :operator_id, :value => params[:operator_id] %>
<div><%= f.submit "Log in" %></div>
<% end %>
<%= render "devise/shared/links" %>
Finally, in order to authenticate admins before accessing the cab details, I added the following to the cabs_controller:
before_filter :authenticate_admin!
The problem is I am unable to submit the admin form. The form doesn't respond when I submit the admin credentials. Where am I going wrong?
You have to add :operator_id to Devise's permitted parameters
Take a look here
Essentially, you want to go with following in application_controller.rb:
before_action :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) do |u|
u.permit(:email, :password, :password_confirmation, :operator_id) #add :operator_id
end
end
Related
The authentication system in my app is handled by devise and now I want each user in my system to belong to an organisation. So each organisation will have multiple users.
When signing up, each user will select which organisation they want to join.
When a user is signing up, and they select and organisation from a combo-box, they get the following error:
ActiveRecord::AssociationTypeMismatch in Devise::RegistrationsController#create
Organisation(#70213198483780) expected, got "1" which is an instance of String(#70213152374240)
The following is what my source code looks like:
app/models/organisation.rb
class Organisation < ApplicationRecord
has_many :users
end
app/models/user.rb
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable
has_many :activities
belongs_to :organisation
end
app/views/devise/registrations/new.html.erb
<h2>Sign up</h2>
<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
<%= render "devise/shared/error_messages", resource: resource %>
<div class="field">
<%= f.label :email %><br />
<%= f.email_field :email, autofocus: true, autocomplete: "email" %>
</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: "new-password" %>
</div>
<div class="field">
<%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation, autocomplete: "new-password" %>
</div>
<div class="field">
<%= f.label :organisation %><br />
<%= f.select :organisation, Organisation.all.collect { |o| [ o.organisation_name, o.id ] }%>
</div>
<div class="actions">
<%= f.submit "Sign up" %>
</div>
<% end %>
<%= render "devise/shared/links" %>
app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
before_action :authenticate_user!
before_action :configure_sign_up_params, if: :devise_controller?
protected
# If you have extra params to permit, append them to the sanitizer.
def configure_sign_up_params
devise_parameter_sanitizer.permit(:sign_up, keys: [:organisation])
end
end
I suggest you should change in your form to
<%= f.select :organisation_id, Organisation.all.collect { |o| [ o.organisation_name, o.id ] }%>
Because the dropdown makes organisation.name as key and organisation.id as value.
Then change devise_parameter_sanitizer.permit(:sign_up, keys: [:organisation_id]) to allow organisation_id to be assigned to user
Instead of using collect on Organisation.all, use Organisation.all.pluck(:name, :id). It will give same result as but a more optimised query.
This is a very easy question I am using devise for authentication...So I am trying to modify my sign up .I am trying to add a radio button on my sign up but it is giving me error .undefined method `status' for User:0x00000001a66368. So i want to know why i can't use radio button on my sign up page
[registration/new.html.erb]
<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 %> <% if #validatable %><i>(<%= #minimum_password_length %> characters minimum)</i><% end %><br />
<%= f.password_field :password, autocomplete: "off" %></div>
<div><%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation, autocomplete: "off" %></div>
<div >
<%= f.label 'InActive' do %>
<%= f.radio_button :status,'In Active'%>
<% end %>
</div>
<div><%= f.submit "Sign up" %></div>
<% end %>
<%= render "devise/shared/links" %>
[user.rb]
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_many :posts
has_many :comments
validates :status,presence:true
validates :name, presence: true
def self.find_role(id)
User.find(id).roles
end
end
You need to add status field in the user table.
rails g migration add_user_status_to_user user_status:boolean
rake db:migrate
Then , In application controller, use strong parameters
class ApplicationController < ActionController::Base
before_action :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) << [:user_status]
end
end
rails generate migration add_status_to_user status:boolean
rake db:migrate
You need to by pass Strong Parameters to add additional new attributes to the sign up page.
class ApplicationController < ActionController::Base
before_action :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up).push(:status)
end
end
i am having two tables employee , and company. i want to register the company name of an employee while Employee is registering by using the devise sign_up action. how to write devise parameter sanitiser method to save the company name while an employee is registering?
The trick is using accepts_nested_attributes_for and overriding the sign_up_params method on the registrations controller.
1. Set up the User model to accept attributes for company
class User < ActiveRecord::Base
belongs_to :company
accepts_nested_attributes_for :company
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
end
2. Override the default Registrations controller
# config/routes.rb
Rails.application.routes.draw do
# ...
devise_for :users, controllers: { registrations: "registrations" }
end
# app/controllers/registrations_controller.rb
class RegistrationsController < Devise::RegistrationsController
# GET /users/sign_up
def new
#user = User.new(company: Company.new)
end
def sign_up_params
params.require(:user).permit(
:email, :password, :password_confirmation,
company_attributes: [:name]
)
end
end
By digging into the source of Devise::RegistrationsController we can se that it calls build_resource(sign_up_params) which is about equivalent to User.new(sign_up_params). So we can simply add our own params handling by declaring our own sign_up_params method.
Note that in sign_up_paramswe use the built Rails 4 strong parameter handling instead of the Devise sanitized params which is a home rolled solution that predates Rails 4. It might be possible to do it with Devise sanitized params but there is no real reason unless you have to have backwards compatibility with Rails 3.
3. Customize the Registration form
To get the correct params hash we want the company name input to have the following name attribute:
user[company_attributes][name]
Rails has a nice helper called fields_for which lets us do that:
<%# app/views/devise/registrations/new.html.erb %>
<h2>Sign up</h2>
<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
<%= devise_error_messages! %>
<div class="field">
<%= f.label :email %><br />
<%= f.email_field :email, autofocus: true %>
</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>
<fieldset>
<legend>Company</legend>
<%= f.fields_for :company do |c| %>
<div class="field">
<%= c.label :name %><br />
<%= c.text_field :name%>
</div>
<% end %>
</fieldset>
<div class="actions">
<%= f.submit "Sign up" %>
</div>
<% end %>
<%= render "devise/shared/links" %>
Notice that fields_for gives us a new form builder instance in the block (c) which we create our nested inputs from.
4. Beer.
for adding custom info in sign_up form Try this :
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
before_action :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) { |u| u.permit( :company_name, :email,:password, :password_confirmation ) }
end
end
and change in your views/devise/registrations/new.html.erb.
<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
<%= devise_error_messages! %>
<div class="field">
<%= f.label :company_name %><br />
<%= f.text_field :company_name %>
</div>
<% end %>
I'm creating a project that allows users to sign in and refer other users once they are signed in. The users have_many referrals and the referrals belongs_to users. I would like to have a page that, once a current user signs in, they can input a referral with the params: name, and referral_email. But this is a collaborative project, and the person who set up the user authentication used devise. Currently, I'm getting the following error:
undefined method `resource' for #<ReferralsController:0x007fb75735aa00>
User Controller:
class UsersController < ApplicationController
def new
end
end
Referral Controller:
class ReferralsController < ApplicationController
def new
#referral = Referral.new
end
def create
#referral = current_user.referrals.new(referral_params)
if #referral.save
redirect_to #referral
else
render 'new'
end
end
def show
#referrals = current_user.find_by_user_id(params[:user_id]).referrals.all
end
def index
#referrals = current_user.referrals.all
end
def edit
#referral = Referral.find(params[:id])
end
def update
#referral = Referral.find(params[:id])
if #referral.update(referral_params)
redirect_to #referral
else
render 'edit'
end
end
def destroy
#referral = Referral.find(params[:id])
#referral.destroy
redirect_to referral_path
end
private
def referral_params
params.require(:referral).permit(:name, :email, :user_id)
end
end
User Model:
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
has_many :referrals
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
include RoleModel
# attr_accessible :email, :password, :password_confirmation, :school_name, :sport, :roles, :roles_mask
roles_attribute :roles_mask
roles :admin, :coach, :guest
end
Referral Model
class Referral < ActiveRecord::Base
belongs_to :user
end
User view:
<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 :school_name %><br />
<%= f.text_field :school_name %></div>
<div><%= f.label :sport %><br />
<%= f.text_field :sport %></div>
<div><%= f.label :password %><br />
<%= f.password_field :password, autocomplete: "off" %></div>
<div><%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation, autocomplete: "off" %></div>
<div><%= f.submit "Sign up" %></div>
<% end %>
<%= render "devise/shared/links" %>
Referral view:
<h2>Refer a coach </h2>
<%= form_for ([current_user, #referral]), :html => { :mulitpart => true } do |f| %>
<%= devise_error_messages! %>
<div><%= f.label :referral %><br />
<%= f.text_field :referral %></div>
<div><%= f.label :referral_email %><br />
<%= f.email_field :referral, autofocus: true %></div>
<div><%= f.submit "Refer This Coach" %></div>
<% end %>
Routes:
Blog::Application.routes.draw do
devise_for :users
resources :users do
resources :referrals
end
get 'sessions/new'
get 'users/new'
resources :articles do
resources :comments
end
root 'welcome#index'
end
The problem is coming from the devise_error_messages! in your referrals view - remove it. Only the user resource is set up to work with devise, nothing else.
As stated in the comments, you should reconsider having referrals be a nested resource under users - there isn't really any advantage to do so the way you are using it, and lots of room for error. Keep it simple!
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.