I'm following along Railscasts #250 Authentication from Scratch but have an issue where the Password Confirmation can be different from the Password and the user will still be created.
..model/dealer.rb:
class Dealer < ActiveRecord::Base
attr_accessor :password
before_save :encrypt_password
validates_confirmation_of :password
validates_presence_of :password, :on => :create
def encrypt_password
if password.present?
self.password_salt = BCrypt::Engine.generate_salt
self.password_hash = BCrypt::Engine.hash_secret(password, password_salt)
end
end
end
..controllers/dealers_controller.rb
class DealersController < ApplicationController
def new
#dealer = Dealer.new
end
def create
#dealer = Dealer.new(dealer_params)
if #dealer.save
redirect_to root_url, :notice => "Signed Up!"
else
render "new"
end
end
private
def dealer_params
params.require(:dealer).permit(:email, :password)
end
end
..views/dealers/new.html/erb
<%= form_for #dealer do |f| %>
<p>
<%= f.label :email %><br>
<%= f.text_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>
<p class="button"><%= f.submit %></p>
Any ideas what I need to do for this to work? Two people in the comments of the Railscast had the same issue but no answer.
Have you tried to add password_confirmation to your allowed params like this:
def dealer_params
params.require(:dealer).permit(:email, :password, :password_confirmation)
end
If this doesn't help try to generate accessor for password_confirmation too:
attr_accessor :password, :password_confirmation
Related
How do I enable the Superadmin to actually create Users? Do I need a policy CreateusersPolicy? My code currently takes me to a page/form where I can create a user, but it doesn't actually create the user.
Please let me know if I need to include more information!
config/routes.rb
Rails.application.routes.draw do
devise_for :users
resources :users, except: :create
root "pages#home"
get "index" => "users#index"
get 'create_user' => 'users#create', as: :create_user
controllers/application_controller.rb
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
include Pundit
protect_from_forgery
def authorize_superadmin
redirect_to root_path, alert: 'Access Denied' unless current_user.superadmin?
end
end
I also don't know what to put here in the create section.
controllers/users_controller.rb
class UsersController < ApplicationController
before_filter :authenticate_user!
#before_filter :authorize_superadmin, except [:show]
#after_action :verify_authorized
def create
# user create code (can't get here if not admin)
end
def index
#users = User.all
authorize User
end
def show
#user = User.find(params[:id])
authorize #user
end
def update
#user = User.find(params[:id])
authorize #user
if #user.update_attributes(secure_params)
redirect_to users_path, :notice => "User updated."
else
redirect_to users_path, :alert => "Unable to update user."
end
end
def destroy
user = User.find(params[:id])
authorize user
user.destroy
redirect_to users_path, :notice => "User deleted."
end
private
def secure_params
params.require(:user).permit(:role)
end
end
views/users/create.html.erb
<%= form_for User.new, url: create_user_path do |f| %>
<div><%= f.label :first_name %><br />
<%= f.text_field :first_name, autofocus: true %></div>
<div><%= f.label :last_name %><br />
<%= f.text_field :last_name, autofocus: true %></div>
<div><%= f.label :email %><br />
<%= f.email_field :email, autofocus: true %></div>
<div><%= f.label :phone_number%><br />
<%= f.phone_field :phone_number, autofocus: true %></div>
<div><%= f.label :street %><br />
<%= f.text_field :street, autofocus: true %></div>
<div><%= f.label :city %><br />
<%= f.text_field :city, autofocus: true %></div>
<div><%= f.label :state %><br />
<%= f.text_field :state, autofocus: true %></div>
<div><%= f.label :zip %><br />
<%= f.text_field :zip, 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.submit "Create" %></div>
<% end %>
app/polices/user_policy.rb
class UserPolicy
attr_reader :current_user, :model
def initialize(current_user, model)
#current_user = current_user
#user = model
end
def index?
#current_user.superadmin?
end
def show?
#current_user.superadmin? or #current_user == #user
end
def update?
#current_user.superadmin?
end
def destroy?
return false if #current_user == #user
#current_user.superadmin?
end
def permitted_attributes
if #current_user.superadmin?
[:role]
else
[:name, :email]
end
end
end
You don't have a create? method in the UserPolicy file so you aren't actually authorizing anything (as far as I can tell).
It should read like this:
# app/policies/user_policy.rb
def create?
#current_user.superadmin?
end
# app/controllers/users_controller.rb
def create
authorize User
# rest of method to create user
end
Also, you don't need to (or want to IMO) have the authorize_superadmin method (you do have the before_filter commented out in the controller, so you aren't calling it) because a) you will call the authorize method in your action and this would be redundant and b) you want to keep your authorization logic in one location: the UserPolicy class. If the authorization fails, it will raise an exception and will not call the rest of the action.
The Pundit documentation is a great resource to get everything setup, but it does take a little bit of trial and error.
I also highly suggest that you create an ApplicationPolicy that you inherit all of your model specific authorization from so that you can catch things that you may not have defined. It is all in the documentation.
Rails 4, Devise 3.0.3, Oauth-facebook
I've added two additional parameters in my User model - :name, :uid and trying to save it in my users table from my form (route /users/sign_up). But as result i receive record in table, which contains only default values for fields :name and :uid instead of values, which i put in my text_fields.
In console i've got the following message:
Unpermitted parameters: name, uid
WARNING: Can't mass-assign protected attributes for User: password_confirmation
app/models/user.rb:31:in `new_with_session'
Here is my user.rb model. I've tried to remove these fiels from attr_accessible but it gives no result.
class User < ActiveRecord::Base
attr_accessible :oauth_expires_at, :oauth_token, :oauth_secret, :email, :password, :uid, :provider, :name
default_scope -> {order('created_at ASC')}
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable,
:omniauthable, :omniauth_providers => [:facebook]
has_many :microposts, :primary_key => "uid", dependent: :destroy
# validates :uid, presence: true
def self.find_for_facebook_oauth(auth, signed_in_resource=nil)
user = User.where(:provider => auth.provider, :uid => auth.uid).first
unless user
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
user
end
def self.new_with_session(params, session)
super.tap do |user|
if data = session["devise.facebook_data"] && session["devise.facebook_data"]["extra"]["user_hash"]
user.email = data["email"]
end
end
end
end
Here is my users/omniauth_callbacks_controller.rb (without facebook method). I've tried to apply different advises related to before_filter, but it still does not work
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
before_filter :configure_permitted_parameters
def create
super
end
private
def configure_permitted_parameters
params.require(:user).permit(:name, :uid, :provider)
end
end
Here is my view-form ()
Sign up
<%= link_to "Sign in with Facebook", user_omniauth_authorize_path(:facebook) %>
<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name)) do |f| %>
<%= devise_error_messages! %>
<div><%= f.label :name %> <br />
<%= f.text_field :name, :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.label :uid %><br />
<%= f.text_field :uid %></div>
<div><%= f.submit "Sign up" %></div>
<% end %>
<%= render "devise/shared/links" %>
Could you help me, i don't understand what am i doing wrong. How to configure whitelist for my strong params to receive proper values (which user put in view-form) ?
All my source code is available here: https://github.com/DavydenkovM/d23m
Thanks in advance!
UPDATE
I've remove attr_accessible fields and update my controller. But the problem with unpermitted params name and uid at the same point. Now my controller looks like:
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
before_filter :configure_permitted_parameters, if: :devise_controller?
def facebook
#user = User.find_for_facebook_oauth(request.env["omniauth.auth"], current_user)
if #user.persisted?
sign_in_and_redirect #user, :event => :authentication #this will throw if #user is not activated
flash[:notice] = I18n.t "devise.omniauth_callbacks.success", :kind => "Facebook"
set_flash_message(:notice, :success, :kind => "Facebook") # if is_navigational_format?
else
redirect_to root_url if user_signed_in?
session["devise.facebook_data"] = request.env["omniauth.auth"]
redirect_to new_user_registration_url
end
end
def create
super
end
#def update
# person = current_account.user.find(params[:id])
# person.update_attributes!(person_params)s
# redirect_to person
#end
private
def configure_permitted_parameters
devise_parameter_sanitizer.for(:users) do |u|
u.permit(:name, :email, :password, :password_confirmation, :uid, :provider)
end
end
end
UPDATE 2.
I'm not clearly understand what is resource in devise_parameter_sanitizer.for(?) and where i need to assign this ?
Please try the following.
def self.find_for_facebook_oauth(auth, signed_in_resource=nil)
user = User.where(:provider => auth.provider, :uid => auth.uid).first
unless user
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]
).permit!(:name, :uid, :provider)
end
user
end
Or
def facebook
#user = User.find_for_facebook_oauth(request.env["omniauth.auth"].permit!(:name, :uid, :provider), current_user)
if #user.persisted?
sign_in_and_redirect #user, :event => :authentication #this will throw if #user is not activated
flash[:notice] = I18n.t "devise.omniauth_callbacks.success", :kind => "Facebook"
set_flash_message(:notice, :success, :kind => "Facebook") # if is_navigational_format?
else
redirect_to root_url if user_signed_in?
session["devise.facebook_data"] = request.env["omniauth.auth"]
redirect_to new_user_registration_url
end
end
Then try this
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) { |u| u.permit(:name, :email, :password, :password_confirmation, :uid, :provider) }
end
attr_accessible is not available in Rails 4 because Strong Parameters is now used by default. It appears you are already using strong parameters, so you should simply remove the line from your user model with attr_accessible in it.
I'm using carrierwave to upload files/images to my application. I'm storing the files through Amazon AWS. The upload works great for images but when trying to add .PDF's I'm receiving a "rollback transaction" error in my server logs and I'm not sure why.
Started POST "/restaurants" for 127.0.0.1 at 2013-06-21 14:39:16 -0400
Processing by RestaurantsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"filAk5Jh++qmb7owXVgYin2C4nq2O+09gMeQV27gKeU=", "restaurant"=>{"name"=>"The Stumble Inn", "address"=>"", "phone"=>"", "description"=>"", "image"=>#<ActionDispatch::Http::UploadedFile:0x00000101da3f98 #original_filename="stumble.jpg", #content_type="image/jpeg", #headers="Content-Disposition: form-data; name=\"restaurant[image]\"; filename=\"stumble.jpg\"\r\nContent-Type: image/jpeg\r\n", #tempfile=#<File:/var/folders/6b/tq59gs0d1f7bp_zg41cf6fqm0000gn/T/RackMultipart20130621-40432-124zf2w>>, "remote_image_url"=>"", "menu"=>#<ActionDispatch::Http::UploadedFile:0x00000101da3d18 #original_filename="menu.pdf", #content_type="application/pdf", #headers="Content-Disposition: form-data; name=\"restaurant[menu]\"; filename=\"menu.pdf\"\r\nContent-Type: application/pdf\r\n", #tempfile=#<File:/var/folders/6b/tq59gs0d1f7bp_zg41cf6fqm0000gn/T/RackMultipart20130621-40432-3cwvjc>>}, "commit"=>"Create Restaurant"}
(0.2ms) begin transaction
(0.2ms) rollback transaction
Redirected to http://localhost:3000/restaurants
class MenuUploader < CarrierWave::Uploader::Base
include CarrierWave::RMagick
# Choose what kind of storage to use for this uploader:
storage :fog
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
end
class Restaurant < ActiveRecord::Base
attr_accessible :address, :description, :name, :phone, :image, :remote_image_url, :menu
mount_uploader :image, ImageUploader
mount_uploader :menu, ImageUploader
end
new.html.erb
<h1>Add new restaurant</h1>
<%= form_for(#restaurant, :html => {:multipart => true}) do |f| %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.label :address %>
<%= f.text_field :address %>
<%= f.label :phone %>
<%= f.text_field :phone %>
<%= f.label :description %>
<%= f.text_field :description %>
<%= f.label :upload_image %>
<%= f.file_field :image %>
<%= f.label :remote_image_url, "or image URL:" %>
<%= f.text_field :remote_image_url %>
<%= f.label :upload_menu %>
<%= f.file_field :menu %><br/><br/>
<%= f.submit "Create Restaurant" %>
<% end %>
class RestaurantsController < ApplicationController
def new
#restaurant = Restaurant.new
end
def create
#restaurant = Restaurant.new(params[:restaurant])
#restaurant.save
redirect_to restaurants_path
end
I realized that I had a type in the Restaurant model.
mount_uploader :menu, ImageUploader
should be:
mount_uploader :menu, MenuUploader
I've problem with my "subscriber". It should just add an email to db with symptom active/inactive. It gaves me this error - undefined method `[]' for nil:NilClass
Extracted source (around line #2):
1: <div id="subscriber">
**2: <%= form_for #subscriber do |f| %>**
3: <%= f.label :email %>
4: <%= f.text_field :email %>
5: <%= f.hidden_field :active, :value => true %>
Here is model:
class Subscriber < ActiveRecord::Base
attr_accessor :email, :active
validates_format_of :email, :with => /\A([^#\s]+)#((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i
def initialize(attributes = {})
attributes.each do |name, value|
send("#{name}=", value)
end
end
def persisted?
false
end
end
This is my view:
<div id="subscriber">
<%= form_for #subscriber do |f| %>
<%= f.label :email %>
<%= f.text_field :email %>
<%= f.hidden_field :active, :value => true %>
<%= f.submit t('.submit') %>
<% end %>
</div>
Here is controller:
class SubscribersController < ApplicationController
def create
#subscriber = Subscriber.new(params[:subscriber])
if #subscriber.valid?
flash[:notice] = "Thx for subscription"
#subscriber.save
redirect_to root_url
else
render :action => 'new'
end
end
end
Here are routes:
resources :subscribers
I'm new with RoR, so if you need some more logs or info let me know. Thx alot.
How to validate password with confirm password in rails 3.2
my code not work
you can tell where my error
I've tried many variations changing the code in the controller.
Password saves but not validated to the password confirm field and password field.
help me please, help me )))
views
<%= form_for :password, :url => { :action => "change_password" }, :id => #user do |f| %>
<% if #user.errors.any? %>
<div class="error_messages">
<h2>Form is invalid</h2>
<ul>
<% for message in #user.errors.full_messages %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<%= f.password_field :password %>
<%= f.password_field :password_confirmation %>
<%= f.submit "Save", :class => "button blue" %>
<% end %>
User Controller
def change_password
#page_title = "Changing Zetfon account password"
#user = current_user
if request.post?
#user.password = Digest::SHA1.hexdigest(params[:password][:password])
if #user.save
redirect_to :action => 'profile'
flash[:status] = "Your password was changed. Next time you sign in use your new password."
else
flash[:status] = _('Your password not changed')
render :action => "change_password"
end
end
end
User Model
validates_confirmation_of :password
attr_accessible :password_confirmation
attr_accessor :password
add the following line to your model
validates :password, confirmation: true
Is it too late to simply use has_secure_password? You can learn about it in this RailsCast:
http://railscasts.com/episodes/270-authentication-in-rails-3-1
I'm not sure why you have if request.post?. Isn't that already determined by your route?
According to the documentation for validates_confirmation_of, I think you might need to add:
validates_presence_of :password_confirmation, :if => :password_changed?
Here's the documentation:
http://apidock.com/rails/ActiveModel/Validations/HelperMethods/validates_confirmation_of
The documentation seems to indicate that you don't need attr_accessible :password_confirmation either.
I hope that helps.