I have implemented a user authentication system in rails using the gem 'bcrypt';I would like to insert a current password field to the edit form to make the changes to the password.
How can do this?
class User < ActiveRecord::Base
before_save { self.email = email.downcase}
before_create :create_remember_token
#Associations
has_one :profile
has_many :posts
#validations
validates :name, presence: true, length: {maximum: 50}
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
validates :email, presence: true, format: {with: VALID_EMAIL_REGEX}, uniqueness: {case_sensitive: false}
has_secure_password
validates :password, length: {minimum: 6}
def User.new_remember_token
SecureRandom.urlsafe_base64
end
def User.digest(token)
Digest::SHA1.hexdigest(token.to_s)
end
private
def create_remember_token
self.remember_token = User.digest(User.new_remember_token)
end
end
<% provide(:title, "Edit user") %>
<h1>Update your profile</h1>
<div class="row">
<div class="span6 offset3">
<%= form_for(#user) do |f| %>
<%= render 'shared/error_messages' %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.label :email %>
<%= f.text_field :email %>
<%= f.label :password %>
<%= f.password_field :password %>
<%= f.label :password_confirmation, "Confirm Password" %>
<%= f.password_field :password_confirmation %>
<%= f.submit "Save changes", class: "btn btn-large btn-primary" %>
<% end %>
</div>
</div>
Thank you
In your view file:
<%= f.label :current_password %>
<%= f.password_field :current_password %>
Also make sure you permit the current_password parameter in your controller.
I assumed current_password attr is already defined by has_secured_password.
Related
i am having a problem where i want to upload images
Say i have clicked the file_field button and uploaded 'test.jpg' image, now when i click the file_field button to upload another image, it overwrites the previous ones , i want to make it happen so that it keeps on appending images whenever we upload more images instead of replacing itself
by reading docs and other peoples questions ,what i came to know is that i need to add
config.active_storage.replace_on_assign_to_many = false
inside config/application.rb,
few even said we have to put it inside config/environments/development.rb
so i placed that code in both of them and still the file_field keeps overwriting whenever i try to upload it again
pages_controller.eb
class PagesController < ApplicationController
def index
end
# GET to /pages/new
def new
#order = Order.new
end
# POST to /pages/new
def create
# Inserts data into the Orders table
#order = Order.new(order_params)
end
private
def order_params
params.require(:order).permit(:paper_size, :color, :quantity, :type, :description, :first_name, :last_name, :phone_numnber, :email, contents:[] )
end
end
order.rb (model)
class Order < ApplicationRecord
validates :paper_size, presence: true
validates :color, presence: true
validates :quantity, presence: true
validates :type, presence: true
validates :first_name, presence: true
validates :last_name, presence: true
validates :phone_number, presence: true
validates :email, presence: true
has_many_attached :contents
end
new.html.erb
<%= form_for #order, url: new_page_path do |f| %>
<div class="container">
<h1 class="text-center">Order From Home!</h1>
<div class="row">
<div class="col-md-4 col-md-offset-4">
<%= f.label :first_name%>
<%= f.text_field :first_name, class:"form-control" %><br/>
<%= f.label :last_name %>
<%= f.text_field :last_name, class:"form-control" %><br/>
<%= f.label :phone_number %>
<%= f.text_field :phone_number, class:"form-control" %><br/>
<%= f.label :email %>
<%= f.text_field :email, class:"form-control" %><br/>
<%= f.label :content %>
<%= f.file_field :content, multiple: true %><br/>
<%= f.label :paper_size %>
<%= f.select :paper_size, ['A4', 'B4'], { prompt: 'Select' }, class:'form-select' %><br/>
<%= f.label :color %>
<%= f.select :color, ['Black & White', 'Color'], { prompt: 'Select' }, class:'form-select' %><br/>
<%= f.label :quantity %>
<%= f.select :quantity, options_for_select(0..500), { prompt: "Select" }, class:'form-select' %><br/>
<%= f.label :description %>
<%= f.text_area :description, class:"form-control" %><br/>
<div class="btn-order">
<%= f.submit %>
</div>
</div>
</div>
</div>
<% end %>
I have a users signup form and once a users signs up he is redirected to users details forms.
user signup form.
<%= form_for(#user, :html => { multipart: true, class: "form-horizontal", role: "form"}) do |f| %>
<%= f.label :email, class: "required" %>
<%= f.email_field :email, required: true %>
<%= f.label :password, class: "required" %>
<%= f.password_field :password, required: true %>
<%= f.label :password_confirmation, class: "required" %>
<%= f.password_field :password_confirmation, required: true %>
<%= f.submit 'Sign up' %>
<% end %>
user details forms
<%= form_for(#user, :html => { multipart: true, class: "form-horizontal", role: "form"}) do |f| %>
<%= f.label :user_firstname, "First Name", class: "required" %>
<%= f.text_field :user_firstname, required: true %>
<%= f.label :user_lastname, "Last Name", class: "required" %>
<%= f.text_field :user_lastname, required: true %>
<%= f.submit 'Save' %>
<% end %>
I want to add a feature so that admin can add a users who doesn't have a email and admin just adds a details in users details form and submits and user is created.
What I have done is, I have added a route and added a method in user controller and this is the error I am getting There was an error adding family. Try again . Please help me fix this
Routes
get 'adduser', to:'users#adduser'
post 'adduser', to:'users#create_user'
User controller
def adduser
#user=User.new
end
def create_user
#user=User.new(user_params)
if #user.save
flash[:success] = "User successfully added" redirect_to main_admin_path
else
flash[:danger] = "There was an error adding user. Try again" redirect_to main_admin_path
end
end
<%= form_for(#user, url: adduser_path, :html => { multipart: true, class: "form-horizontal", role: "form"}) do |f| %>
<%= f.label :user_firstname, "First Name", class: "required" %>
<%= f.text_field :user_firstname, required: true %>
<%= f.label :user_lastname, "Last Name", class: "required" %>
<%= f.text_field :user_lastname, required: true %>
<%= f.submit 'Save' %>
<% end %>
Validations
attr_accessor :remember_token, :activation_token, :reset_token
before_create :confirmation_token
has_secure_password
validates :email, presence: true, uniqueness: {case_sensitive: false}, format: { with: VALID_EMAIL_REGEX }
validates_attachment :document
validates_confirmation_of :password
At first, you need to create a migration and add a new column to the users table. I think it is better to keep info about admin creating in the db (if you don't want to store it, just add :created_by_admin to attr_accessor list instead of this step).
add_column :users, :created_by_admin, :boolean, default: false, null: false
Add this new field to the form ('added by admin'):
<%= f.hidden_field :created_by_admin, value: true %>
Add condition to email validation:
validates :email, presence: true, uniqueness: { case_sensitive: false },
format: { with: VALID_EMAIL_REGEX }, unless: :created_by_admin?
Use an attr_accessor in your model, if you don't want any changes to your existing schema.
models/user.rb
class User
attr_accessor :with_email_optional
# Run these validations only if `self.with_email_optional` is not set OR set to `false`
validates :email,
presence: true,
uniqueness: { case_sensitive: false },
format: { with: VALID_EMAIL_REGEX },
unless: :with_email_optional
end
And in your users controller for admin (i don't know what that is called in your application):
def new
#user = User.new
#user.with_email_optional = true
end
private
# To be used in `create` action
def user_params
params.require(:user).permit(..., :with_email_optional)
end
Form
<%= form_for(#user) do |f|
<%= f.hidden_field :with_email_optional, value: f.object.with_email_optional %>
<% end %>
So i am trying to implement a dropdown menu in my edit form for users, i used devise, so this edit form is inside my devise/registrations/edit.html.erb file.
first i get and error for undefined method for :optionselect (which seems understandable since i couldn't find this elsewhere other than this select in form_for rails
so this is wrong.
<div class="field">
<%= f.label :role %><br />
<%= f.select :optionselect, User.options %>
</div>
i also had it like this
<div class="field">
<%= f.label :role %><br />
<%= f.select :role, [['Member', 'member'], ['Astronaut', 'astronaut'], ['Candidate', 'candidate']] %>
but no luck. because it wouldn't persist the changes i made when editing the role of the user.
Also the name doesn't persist when trying to update it. maybe that gives us a lead.
models/user.rb
class User < ActiveRecord::Base
has_many :books
has_many :reviews
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable,
:registerable,
:recoverable,
:rememberable,
:trackable,
:validatable
validates :email, presence: true, uniqueness: true
validates_format_of :email, :with => /\A([^#\s]+)#((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i, :on => :create
validates :password,
:presence => { :on => :create },
:length => { :minimum => 6, :allow_nil => true }
OPTIONS = [
{:role => 'memeber'},
{:role => 'astronaut'},
{:role => 'candidate'}
]
def self.options
OPTIONS.map { |option| option[:role] }
end
end
controllers/users_controller.rb
class UsersController < ApplicationController
def index
binding.pry
#users = User.all
end
def show
#user = User.find(params[:id])
end
def update
#user = User.find(params[:id])
if #user.update!(user_params)
redirect_to :action => 'show', :id => #user
else
render :action => 'edit'
end
end
private
def user_params
params.require(:user).permit(:name, :email, :role)
end
end
devise/registration/edit.html.erb
<h2>Edit <%= resource_name.to_s.humanize %></h2>
<%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f| %>
<%= devise_error_messages! %>
<div class="field">
<%= f.label :name %><br />
<%= f.text_field :name, autofocus: true %>
</div>
<div class="field">
<%= f.label :role %><br />
<%= f.select :optionselect, User.options %>
</div>
<div class="field">
<%= f.label :email %><br />
<%= f.email_field :email, autofocus: true %>
</div>
<% if devise_mapping.confirmable? && resource.pending_reconfirmation? %>
<div>Currently waiting confirmation for: <%= resource.unconfirmed_email %></div>
<% end %>
<div class="field">
<%= f.label :password %> <i>(leave blank if you don't want to change it)</i><br />
<%= f.password_field :password, autocomplete: "off" %>
</div>
<div class="field">
<%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation, autocomplete: "off" %>
</div>
<div class="field">
<%= f.label :current_password %> <i>(we need your current password to confirm your changes)</i><br />
<%= f.password_field :current_password, autocomplete: "off" %>
</div>
<div class="actions">
<%= f.submit "Update" %>
</div>
<% end %>
<h3>Cancel my account</h3>
<p>Unhappy? <%= button_to "Cancel my account", registration_path(resource_name), data: { confirm: "Are you sure?" }, method: :delete %></p>
<%= link_to "Back", :back %>
Let me know if you need more information
edit.html.erb
<%= f.select(:role, User::USER_OPTIONS) %>
models/user.rb
USER_OPTIONS = ["memeber", "astronaut", "candidate"]
I am having trouble articulating the exact issue I am facing, but I will try with a brief descriptions and code.
I am trying to add a feature to a simple existing app that allows the user to crop an uploaded image for an avatar. I do the file selection on the same view that allows the user to update their password and other various account options. The user submits that form which then renders the view for the cropping feature. The issue is that from the crop view, the submission fails because it fails validation of parameters from the previous form. Basically I would like the form to all be submitted at the same time but from two different views.
user.rb
class User < ActiveRecord::Base
attr_accessible :name, :email, :password, :password_confirmation, :avatar,
:crop_x, :crop_y, :crop_w, :crop_h
validates :name, presence: true, length: { maximum: 50 }
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
validates :email, presence: true, format: { with: VALID_EMAIL_REGEX },
uniqueness: { case_sensitive: false }
validates :password, presence: true, length: { minimum: 6 }
validates :password_confirmation, presence: true
mount_uploader :avatar, AvatarUploader
attr_accessor :crop_x, :crop_y, :crop_w, :crop_h
after_update :crop_avatar
def crop_avatar
avatar.recreate_versions! if crop_x.present?
end
end
I have tried several different things to remedy this. I am sure I am missing a fundamental concept. Any ideas?
users_controller.rb
def update
#user = User.find(params[:id])
if #user.update_attributes(params[:user])
if params[:user][:avatar].present?
render 'crop'
else
sign_in #user
redirect_to #user, notice: "Successfully updated user."
end
else
render 'edit'
end
end
edit.html.erb
<% provide(:title, "Edit user") %>
<h1>Update your profile</h1>
<div class="row">
<div class="span6 offset3">
<%= form_for #user, :html => {:multipart => true } do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<%= f.label :avatar %>
<%= f.file_field :avatar %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.label :email %>
<%= f.text_field :email %>
<%= f.label :password %>
<%= f.password_field :password %>
<%= f.label :password_confirmation, "Confirm Password" %>
<%= f.password_field :password_confirmation %>
<%= f.submit "Save changes", class: "btn btn-large btn-primary" %>
<% end %>
</div>
</div>
crop.html.erb
<% provide(:title, 'Crop Avatar') %>
<h1>Crop Avatar</h1>
<div class="row">
<div class="span6 offset3">
<%= image_tag #user.avatar_url(:large), id: "cropbox" %>
<h4>Preview</h4>
<div style="width:100px; height:100px; overflow:hidden">
<%= image_tag #user.avatar.url(:large), :id => "preview" %>
</div>
<%= form_for #user do |f| %>
<% %w[x y w h].each do |attribute| %>
<%= f.hidden_field "crop_#{attribute}" %>
<% end %>
<div class="actions">
<%= f.submit "Crop" %>
</div>
<% end %>
</div>
</div>
You can't have 2 views for one action. On a second thought why do you need it anyways, i mean you are rendering crop only when params[:user][:avatar] is present and that will be called only when you'll submit your edit.html.erb template. I think what you can do is have another method in controller with name crop and there update user's avatar with the dimention's specified.
I've got an address form nested into a user form but cant get the foreign key to fill. I've seen people suggest using a hidden field, but that seems to be a bad idea from a security standpoint. How exactly do you set the foreign key using the controller? Right now I'm getting Address user can't be blank error when I try to submit
MVC below
user\new.html.erb
<div>
<%= form_for(#user) do |f| %>
<%= render 'shared/error_messages' %>
<%= f.label :rank %>
<%= f.text_field :rank %>
<%= f.label :firstName, "First Name" %>
<%= f.text_field :firstName %>
<%= f.label :lastName, "Last Name" %>
<%= f.text_field :lastName %>
<%= f.label :middleInitial, "Middle Initial" %>
<%= f.text_field :middleInitial %>
<%= fields_for :address do |a| %>
<%= a.label :address %>
<%= a.text_field :address %>
<%= a.label :city %>
<%= a.text_field :city %>
<%= a.label :state %>
<%= a.text_field :state %>
<%= a.label :zip, "Zip Code" %>
<%= a.text_field :zip %>
<% end %>
<%= f.label :email %>
<%= f.text_field :email %>
<%= f.label :dateOfBirth, "Date of Birth" %>
<%= f.text_field :dateOfBirth %>
<%= f.label :MOS, "MOS" %>
<%= f.text_field :MOS %>
<%= f.label :ets_pcsDate, "ETS/PCS Date" %>
<%= f.text_field :ets_pcsDate %>
<%= f.label :phoneNum, "Phone Number" %>
<%= f.text_field :phoneNum %>
<%= f.label :password %>
<%= f.text_field :password %>
<%= f.label :password_confirmation, "Confirmation" %>
<%= f.text_field :password_confirmation %>
<%= f.submit "Sign up" %>
<% end %>
</div>
<h1>Users#new</h1>
<p>Find me in app/views/users/new.html.erb</p>
Models
User
class User < ActiveRecord::Base
attr_accessible :MOS, :dateOfBirth, :ets_pcsDate, :firstName,
:lastName, :middleInitial, :phoneNum, :rank, :email, :password,
:password_confirmation
has_secure_password
has_one :address, dependent: :destroy
accepts_nested_attributes_for :address
before_save { |user| user.email = email.downcase }
before_save :create_remember_token
validates :rank, presence: true
validates :firstName, presence: true, length: { maximum: 15 }
validates :lastName, presence: true, length: { maximum: 20 }
validates :middleInitial, presence: true, length: { maximum: 1 }
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
validates :email, presence: true,
format: { with: VALID_EMAIL_REGEX },
uniqueness: { case_sensitive: false }
validates :dateOfBirth, presence: true
validates :MOS, presence: true
validates :ets_pcsDate, presence: true
validates :phoneNum, presence: true
validates :password, length: { minimum: 6 }
validates :password_confirmation, presence: true
private
def create_remember_token
self.remember_token = SecureRandom.urlsafe_base64
end
end
Address
class Address < ActiveRecord::Base
attr_accessible :address, :city, :state, :zip
belongs_to :user
validates :address, presence: :true
validates :city, presence: :true
validates :state, presence: :true
validates :zip, presence: true
validates :user_id, presence: true
end
Controller
class UsersController < ApplicationController
before_filter :signed_in_user, only: [:index, :edit, :update, :show, :destory]
before_filter :correct_user, only:[:edit, :update]
before_filter :admin_user, only: :destroy
def new
#user = User.new
#user.address.build
end
def create
#user = User.new(params[:user])
#address = #user.build_address(params[:address])
if #user.save
sign_in #user
flash[:success] = "Welcome to B Troop!"
redirect_to #user
else
render 'new'
end
end
def show
#user = User.find(params[:id])
end
def index
#users = User.paginate(page: params[:page])
end
def edit
end
def update
if #user.update_attributes(params[:user])
flash[:success] = "Profile updated"
sign_in #user
redirect_to #user
else
render 'edit'
end
end
def destroy
User.find(params[:id]).destroy
flash[:success] = "User removed"
redirect_to users_path
end
private
def signed_in_user
unless signed_in?
store_location
redirect_to root_path, notice: "Please sign in."
end
end
def correct_user
#user = User.find(params[:id])
redirect_to(root_path) unless current_user?(#user)
end
def admin_user
redirect_to(root_path) unless current_user.admin?
end
end
Removing the user_id validation did the trick.