using devise with rails: current_password being sanitized? - ruby

I've added some parameters to a small User class using the Devise gem and am having some trouble with current_password. On my account update form, I receive the error "Can't be blank" when I update an account and type in the current password. The account is subsequently not updated. I suspect it is being sanitized somewhere which deletes the input and then is read as blank. However I am not sure. I have included anything I thought to be relevant below.
User model:
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
attr_accessible :username, :email, :password, :password_confirmation, :remember_me, :about_me
has_many :microposts
end
Application controller:
class ApplicationController < ActionController::Base
protect_from_forgery
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) { |u| u.permit(:username, :email)}
devise_parameter_sanitizer.for(:sign_in) { |u| u.permit(:username, :email)}
devise_parameter_sanitizer.for(:account_update) { |u| u.permit(:username, :about_me, :email, :password, :password_confirmation, :current_password)}
end
end
password controller:
class Users::PasswordsController < Devise::PasswordsController
def resource_params
params.require(:user).permit(:email, :password, :password_confirmation, :current_password)
end
private :resource_params
end
Registration controller
class Users::RegistrationsController < Devise::RegistrationsController
before_filter :configure_permitted_parameters
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) do |u|
u.permit(:username, :about_me, :email, :password, :password_confirmation)
end
devise_parameter_sanitizer.for(:account_update) do |u|
u.permit(:username, :about_me, :email, :password, :password_confirmation, :current_password)
end
end
end
routes for devise:
devise_for :users, :controllers => {:registrations => "users/registrations", :passwords => "users/passwords" }
the view in question (standard devise /registrations/edit form):
<h2>Edit <%= resource_name.to_s.humanize %></h2>
<%= simple_form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f| %>
<%= f.error_notification %>
<div class="form-inputs">
<%= f.input :email, required: true, autofocus: true %>
<%= f.input :username, required: false, autofocus: true %>
<%= f.input :about_me, required: false, autofocus: true %>
<% if devise_mapping.confirmable? && resource.pending_reconfirmation? %>
<p>Currently waiting confirmation for: <%= resource.unconfirmed_email %></p>
<% end %>
<%= f.input :password, autocomplete: "off", hint: "leave it blank if you don't want to change it", required: false %>
<%= f.input :password_confirmation, required: false %>
<%= f.input :current_password, hint: "we need your current password to confirm your changes", required: true %>
</div>
<div class="form-actions">
<%= f.button :submit, "Update" %>
</div>
<% end %>
<h3>Cancel my account</h3>
<p>Unhappy? <%= link_to "Cancel my account", registration_path(resource_name), data: { confirm: "Are you sure?" }, method: :delete %></p>
Again, the problem is that when the password to confirm changes is typed in, the error message "can't be blank" appears next to the field. Any ideas? Thank you

This is an issue I've had trouble in the past with, and something that requires a little bit of a work-around. By default, Devise's :registerable module allows a user to change their information, and requires the :password and :password_confirmation parameters to be entered. As I understand it, you're trying to require the user to enter and confirm their :current_password.
In order to implement the behavior you're looking for, you'll have to override Devise's RegistrationsController. I also don't think you'll need the PasswordsController, since Devise's RegistrationsController handles that for you. You'll need to write and implement a method that checks the validity of the user's :current_password, and then redirects them to the right places via the update action. You can write the following private method in your Users::RegistrationController class:
def needs_password?(user, params)
user.email != params[:user][:email] ||
params[:user][:password].present? ||
params[:user][:password_confirmation].present?
end
Then revise your update method in User::RegistrationsController as follows:
class Users::RegistrationsController < Devise::RegistrationsController
def update
#user = User.find(current_user.id)
successfully_updated = if needs_password?(#user, params)
#user.update_with_password(devise_parameter_sanitizer.sanitize(:account_update))
else
# remove the virtual current_password attribute
# update_without_password doesn't know how to ignore it
params[:user].delete(:current_password)
#user.update_without_password(devise_parameter_sanitizer.sanitize(:account_update))
end
if successfully_updated
set_flash_message :notice, :updated
# Sign in the user bypassing validation in case their password changed
sign_in #user, :bypass => true
redirect_to after_update_path_for(#user)
else
render "edit"
end
end
Hopefully that will help. You can also refer to Devise's documentation on how to do this: https://github.com/plataformatec/devise/wiki/How-To%3a-Allow-users-to-edit-their-account-without-providing-a-password.

Related

Error: Validation failed: Images imageable must exist , rails-5.0 , paperclip-5

While i was trying to submit the form, following error occured: Validation failed: Images imageable must exist and render the same new.html.erb view.
If i comment the file field in new.html.erb. Product is being created successfully.
ProductsController:
def new
#product = Product.new
end
def create
#product = Product.create!(product_params)
if #product.save
redirect_to products_path, notice: "Product Created Successfully"
else
render "new"
end
end
def product_params
params.require(:product).permit(:name, :quantity, :price, images_attributes: [:id, :photo, :_destroy])
end
new.html.erb:
<%= nested_form_for #product, html: { multipart: true } do |f|%>
<h2>New</h2>
<P> <%= f.label :name %> <%= f.text_field :name %> </P>
<P> <%= f.label :quantity %> <%= f.text_field :quantity %> </P>
<P> <%= f.label :price %> <%= f.text_field :price %> </P>
<%= f.fields_for :images do |p| %>
<p> <%= p.label :photo %> <%= p.file_field :photo %> </p>
<%= p.link_to_remove "Remove Image" %>
<% end %>
<%= f.link_to_add "Add Image", :images %>
<%= f.submit "Add Product" %>
<% end %>
20160725102038_add_image_columns_to_imageable.rb:
class AddImageColumnsToImageable < ActiveRecord::Migration[5.0]
def up
add_attachment :images, :photo
end
def down
remove_attachment :images, :photo
end
end
Model:product.rb
class Product < ApplicationRecord
has_one :variant
has_many :images, as: :imageable, dependent: :destroy
accepts_nested_attributes_for :images, allow_destroy: true
end
Model:image.rb
class Image < ApplicationRecord
belongs_to :imageable, polymorphic: true
has_attached_file :photo, styles: { medium: "300x300>", thumb: "100x100>" }, default_url: "/images/:style/missing.png"
validates_attachment :photo, content_type: { content_type: ["image/jpg", "image/jpeg", "image/png", "image/gif"] }
end
In rails 5, belongs_to makes sure that the associated model must exist.
E.g In this polymorphic association, Image model has belongs_to :imageable and Product model has has_many :images.
So here in new.html.erb we are creating an image, but respective product not exist, so that's why error Image imageable must exist .
Solution
Add optional: true while making an association of belong_to in Image model.
Image Model now looks like:
class Image < ApplicationRecord
belongs_to :imageable, polymorphic: true, optional: true
has_attached_file :photo, styles: { medium: "300x300>", thumb: "100x100>" }, default_url: "/images/:style/missing.png"
validates_attachment :photo, content_type: { content_type: ["image/jpg", "image/jpeg", "image/png", "image/gif"] }
end

Regex not validating correctly in Rails 4 app

I cannot seem to get validation to pass in Rails 4 app using regex for email.
Subscriber.rb
class Subscriber < ActiveRecord::Base
validates_uniqueness_of :email, :case_sensitive => false, message: "You're already subscribed!"
validates_format_of :email, :with => /#/i, message: "Email is invalid"
before_save { self.email = email.downcase if email}
end
No matter how simple my regex is, I get the "Email is invalid" message.
Any ideas or am I doing something obviously wrong (regex isn't a strong suit for me).
Thanks!
_subscribe.html.erb
<%= form_for Subscriber.new do |f| %>
<%= f.text_field :email, :class => "uppercase", :placeholder => "Stay in touch. Enter your email" %>
<%= f.submit :class => "submit uppercase", :value => 'submit' %>
<% end %>
Line that calls the partial:
<%= render :partial => 'shared/subscribe', :subscriber => Subscriber.new %>
subscribers_controller.rb
include SubscribersHelper
def create
#subscriber = Subscriber.new
if #subscriber.save(subscriber_params)
redirect_to(:back)
flash.notice = "You are now subscribed"
else
redirect_to(:back)
flash.alert = "There was an error with your subscription: "
flash.alert += #subscriber.errors.messages.values.join(", ")
end
end
SubscribersHelper.rb
def subscriber_params
params.require(:subscriber).permit(:email)
end
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
validates :email, presence: true, length: { maximum: 255 },
format: { with: VALID_EMAIL_REGEX },
uniqueness: { case_sensitive: false }
Above is a pretty failsafe email RegEx.

How to solve undefined method `permit' for :user:Symbol error in ror-4

Please help me to solve this error.When update action is executing this error is showing.
Error:
NoMethodError in UsersController#update
undefined method `permit' for :user:Symbol
My code snippets are given below.
views/users/edit.html.erb
<h1>Edit your data</h1>
<%= form_for #user,:url => {:action => 'update',:id => params[:id]} do |f| %>
<% if #user.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#user.errors.count, "error") %> prohibited this post from being saved:</h2>
<ul>
<% #user.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<%= f.text_field:name,:value => #edit.name %>
<%= f.email_field:email,:value => #edit.email %>
<%= f.text_field:message,:value => #edit.message %>
<%= f.submit "Update" %>
<% end %>
<%= link_to "Back",users_index_path %>
controller/users_controller.rb
class UsersController < ApplicationController
def index
end
def new
#user=User.new
end
def create
#user=User.new(users_params)
if #user.save
flash[:notice]="Your data is saved succesfully"
flash[:color]="valid"
redirect_to :action => 'index'
else
flash[:alert]="You are entering wrong data"
flash[:color]="invalid"
render :new
end
end
def show
#user=User.all
end
def delete
#user=User.find(params[:id])
if #user.delete
flash[:notice]=#user.name+"has deleted successfully"
flash[:color]="valid"
redirect_to :action => 'index'
else
flash[:alert]=#user.name+"could not delete.Please check it.."
flash[:color]="invalid"
render :show
end
end
def edit
#edit=User.find(params[:id])
#user=User.new
end
def update
#user=User.find(params[:id])
if #user.update_attributes(update_params)
flash[:notice]="Your data has updated successfully"
flash[:color]="valid"
redirect_to :action => 'index'
else
flash[:alert]="Your data could not update..check it.."
flash[:color]="invalid"
render :edit
end
end
private
def users_params
params.require(:user).permit(:name, :email, :message,pets_attributes: [:name, :email,:message])
end
def update_params
params.require (:user).permit(:name,:email,:message,pets_attributes: [:name, :email,:message])
end
end
model/user.rb
class User < ActiveRecord::Base
has_many :pets
accepts_nested_attributes_for :pets
EMAIL_REGEX = /\A[A-Z0-9._%+-]+#[A-Z0-9.-]+\.[A-Z]{2,4}\z/i
validates :name, :presence => true,:length => { :minimum => 5 }
validates :email, :presence => true, :uniqueness => true, :format => EMAIL_REGEX
validates :message, :presence => true
end
Please help me to solve the above error.
You have space between require and (:user). Your current code is equivalent to:
def update_params
params.require(:user.permit(:name,:email,:message,pets_attributes: [:name, :email,:message]))
end
As you can see now, you call permit method on :user symbol and this is direct cause of error.
It should be:
def update_params
params.require(:user).permit(:name,:email,:message,pets_attributes: [:name, :email,:message])
end
BTW having two methods that do exactly same thing is quite pointless.
Check your question:
you have a space after require and before (:user)
Try:
def update_params
params.require(:user).permit(:name,:email,:message,
pets_attributes: [:name, :email,:message])
end
For a better way, you can have just one method:
def user_params
params.require(:user).permit(:name,:email,:message,
pets_attributes: [:name, :email,:message])
end
Instead of having separate filter methods for new and edit, you can have just one method and reuse that in both new and edit.
Just keep things Simply DRY.

Displaying Current User in view through a polymorphic association

I am attempting to display the current users name once they are logged in.
Therefore at the top of the page it would say "Logged in as Patrick". However I have a polymorphic association set up whereby every user that signs up is either a player or a coach.
The polymorphic association is under the label or :tennis_player as both coach and player play tennis.
The code for the view is below.
<div class="container">
<header>
<div class="logo">
<%= link_to(image_tag 'tennis_ball.png', :width => 100, :height => 100) %>
</div>
<div class="slogan">
<h3>Setfortennis</h3>
</div>
<div id="user_nav">
<% if current_user? %>
Logged in as <%= #current_user %>
<%= link_to "log out", log_out_path %>
<% else %>
<%= link_to "Sign Up", sign_up_path %> or
<%= link_to "Log in", log_in_path %>
<% end %>
</div>
</header>
</div>
Here is my application controller
helper_method :current_user?
before_filter :get_user
def current_user?
!!current_user
end
def current_user
#current_user ||= session[:user_id] &&
User.find_by_id(session[:user_id])
end
def check_logged_in
redirect_to( new_session_path, :notice => "You must be logged in to do that!") unless current_user?
end
def get_user
#user = User.new
end
end
And here are my models. Anything else needed to solve let me know!
class Player < ActiveRecord::Base
attr_accessible :about, :club, :first_name, :last_name, :profile_picture, :racket, :ranking, :image
has_attached_file :image, styles: {
thumb: '100x100>',
square: '200x200#',
medium: '300x300>'
}
has_many :videos
has_one :user, :as => :tennis_player
end
class Coach < ActiveRecord::Base
attr_accessible :about, :club, :first_name, :last_name, :profile_picture, :ranking
has_one :user, :as => :tennis_player
end
User Model.
class User < ActiveRecord::Base
attr_accessible :email, :password_hash, :password_salt, :password, :password_confirmation
attr_accessor :password
belongs_to :tennis_player, :polymorphic => true
before_save :encrypt_password
validates_confirmation_of :password
validates_confirmation_of :password, :on => :create
validates_confirmation_of :email
validates_uniqueness_of :password
def self.authenticate(email, password)
user = find_by_email(email)
if user && user.password_hash == BCrypt::Engine.hash_secret(password, user.password_salt)
user
else
nil
end
end
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
You just need to store the right id whenever you create a session. But I would change the design a little. Instead of having two separate tables for Player and Coach, you can create a base class User, and inherit from it.
class User < ActiveRecord::Base
attr_accessible :about, :club, :first_name, :last_name, :profile_picture, :ranking
end
class Player < User
end
class Coach < User
end

Nested Form Doesn't Save Nested Model Rails 3

I am trying to create a form that creates a game and game_players at the same time.
The problem I am having is that when I submit the form, the game is created, but the game_players are not.
I've looked around, but haven't found any helpful answers.
Game Model
class Game < ActiveRecord::Base
belongs_to :league
has_many :game_players, :dependent => :destroy
accepts_nested_attributes_for :game_players
attr_accessible :league_id, :game_date
validate :league_id, :presence => true
end
Game_Player Model
class GamePlayer < ActiveRecord::Base
belongs_to :game
has_many :users
validate :game_id, :presence => true
validate :user_id, :presence => true
end
Game Controller
class GamesController < ApplicationController
def new
#title = "New Game"
#game = Game.new
3.times { #game.game_players.build }
end
def create
#game = Game.new(:league_id => cookies[:league_id])
if #game.save
flash[:success] = "Succesfully Created Game"
redirect_to League.find_by_id(cookies[:league_id])
else
#title = "New Game"
render 'new'
end
end
Form
<%= form_for #game do |f| %>
<%= f.fields_for :game_players do |builder| %>
<p>
<%= builder.label :user_id, "User" %><br />
<%= builder.text_field :user_id %><br />
</p>
<% end %>
<p><%= f.submit "Submit" %></p>
<% end %>
most likely you need to pass :game_players_attributes to attr_accessible since .new respect mass-assignment security

Resources