Syntax error in Rails User Model? - ruby-on-rails

I am getting this error in rails console when trying to create new User:
models/user.rb:32: syntax error, unexpected tSTRING_DEND, expecting ')'
..."#{Time.now.utc}--#{password}"})if self.new_record?
Here is my Model:
class User < ActiveRecord::Base
attr_accessor :password
attr_accessible :name, :email, :password, :password_confirmation
email_regex = /\A[\w+\-.]+#[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i
validates :name, :presence => true
validates :email, :presence => true,
:format => { :with => email_regex },
:uniqueness => { :case_senstive => false }
validates :password, :presence => true,
:confirmation => true,
:length => { :within => 6..40 }
before_save :encrypt_password
def has_password?(submitted_password)
encrypted_password == encrypt(submitted_password)
end
def self.authenticate(email, submitted_password)
user = find_by_email(email)
return nil if user.nil?
return user if user.has_password?(submitted_password)
end
private
def encrypt_password
#generate salt for new user
self.salt = Digest::SHA2.hexdigest("#{Time.now.utc}--#{password}"}) if self.new_record?
#encrypt password; store in encrypted_password
self.encrypted_password = encrypt_password
end
#encrypt with salt
def encrypt(pass)
Digest::SHA2.hexdigest("#{self.salt}--#{pass}")
end
end
I am not sure of the error, but console does point to the parentheses after the --#{password}"})
^

You have an extra } symbol right at the end of the string

self.salt = Digest::SHA2.hexdigest("#{Time.now.utc}--#{password}"}) if self.new_record?
Replace Above Line With This
self.salt = Digest::SHA2.hexdigest("#{Time.now.utc}--#{password}") if self.new_record?

change your method
def encrypt_password
#generate salt for new user
self.salt = Digest::SHA2.hexdigest("#{Time.now.utc}--#{password}") if self.new_record?
#encrypt password; store in encrypted_password
self.encrypted_password = encrypt_password
end
syntax error was on
self.salt = Digest::SHA2.hexdigest("#{Time.now.utc}--#{password}"}) if self.new_record?
it should be
self.salt = Digest::SHA2.hexdigest("#{Time.now.utc}--#{password}") if self.new_record?
you have given a extra '}'

Related

How to update a character varying array field on Postgres with Rails 5.2?

My application defines a list of user's preferred activities as an array of strings stored in a Postgres character varying array field.
The field is defined in Postgres DDL as:
preferred_activities character varying[] COLLATE pg_catalog."default" DEFAULT '{}'::character varying[]
The field is initialised by an API which receives a comma separated list of values (userActivities ) such as "CLIMB,RUN,212" with the following instruction:
#user.preferred_activities = userActivities.split(',')
This results in the expected list stored as {CLIMB,RUN,212} in Postgres field and displayed as expected in the view: CLIMB,RUN,212
As the field can also be manually edited, it also appears in user's form where it is initialised with a consistent format:
<%= f.text_field :preferred_activities, value: f.object.preferred_activities.join(',') %>
which provides the expected field value attribute "CLIMB,RUN,212" (displayed as CLIMB,RUN,212).
And then formatted before user's record update:
#user.preferred_activities = user_params[:preferred_activities].split(',')
which produces the following array: ["CLIM", "RUN", "212"]
This update should be straight forward, but for a reason I don't understand, the following SQL instruction is generated:
User Update (0.9ms) UPDATE "users" SET "preferred_activities" = $1, "updated_at" = $2 WHERE "users"."id" = $3
[["preferred_activities", "{LIM,\"RUN\"}"], ["updated_at", "2022-03-17 12:26:25.195321"], ["id", 1]]
The first letter and the last word have disappeared!
I did try other syntaxes for the instruction, which lead to the same result:
#user.preferred_activities = user_params[:preferred_activities]
#user.preferred_activities = "{#{user_params[:preferred_activities]}}"
Do you see any explanation for this behaviour and any solution to properly update this character varying array field?
User model:
class User < ApplicationRecord
extend CsvHelper
# Audit trail setup
audited except: [:encrypted_password, :reset_password_token, :reset_password_sent_at, :remember_created_at,
:sign_in_count, :current_sign_in_at, :last_sign_in_at, :current_sign_in_ip, :last_sign_in_ip,
:confirmation_token, :confirmed_at, :confirmation_sent_at, :unconfirmed_email,
:failed_attempts, :unlock_token, :locked_at]
#validates_with EmailAddress::ActiveRecordValidator, field: :email
# Virtual attribute for authenticating by either username or email
# This is in addition to a real persisted field like 'username'
attr_accessor :login
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :recoverable, :rememberable,
:trackable, :confirmable, :lockable, :password_archivable, :registerable,
:omniauthable, omniauth_providers: %i[keycloakopenid]#, :secure_validatable
before_save :email_format
before_save :name_update
### validations
# validates :current_playground_id, presence: true
validates :email, :presence => true, uniqueness: {scope: :playground_id, case_sensitive: false}, length: { maximum: 100 }
#validates_format_of :email, with: /\A(\S+)#(.+)\.(\S+)\z/
validate :password_confirmed
validate :password_complexity
validates :first_name, presence: true, length: { maximum: 100 }
validates :last_name, presence: true, length: { maximum: 100 }
validates :user_name, presence: true, uniqueness: {scope: :playground_id, case_sensitive: false}, length: { maximum: 100 }
validates :external_directory_id, length: { maximum: 100 }
validates :created_by, presence: true, length: { maximum: 30 }
validates :updated_by, presence: true, length: { maximum: 30 }
#validate :member_of_Everyone_group
validates :organisation, presence: true
belongs_to :organisation
belongs_to :parent, :class_name => "Playground", :foreign_key => "playground_id"
belongs_to :owner, :class_name => "User", :foreign_key => "owner_id"
# Relations
has_and_belongs_to_many :groups
has_many :groups_users
### Translation support
mattr_accessor :translated_fields, default: ['description']
has_many :translations, as: :document
has_many :description_translations, -> { where(field_name: 'description') }, class_name: 'Translation', as: :document
accepts_nested_attributes_for :translations, :reject_if => :all_blank, :allow_destroy => true
accepts_nested_attributes_for :description_translations, :reject_if => :all_blank, :allow_destroy => true
### Public functions
def activity_status
if self.is_active
if not self.locked_at.nil?
"locked"
else
if self.confirmed_at.nil?
"Unconfirmed"
else
if self.sign_in_count == 0
"Confirmed"
else
"Active"
end
end
end
else
"Inactive"
end
end
def principal_group
self.groups_users.find_by(is_principal: true).group_id
end
def password_complexity
# Regexp extracted from https://stackoverflow.com/questions/19605150/regex-for-password-must-contain-at-least-eight-characters-at-least-one-number-a
return if password.blank? || password =~ /^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!#$%^&*-]).{8,70}$/
errors.add :password, 'Complexity requirement not met. Length should be 8-70 characters and include: 1 uppercase, 1 lowercase, 1 digit and 1 special character'
end
def password_confirmed
return if password == password_confirmation
errors.add :password, 'Password and confirmation do not match'
end
### full-text local search
pg_search_scope :search_by_user_name, against: [:user_name, :name, :description],
using: { tsearch: { prefix: true, negation: true } }
def self.search(criteria)
if criteria.present?
search_by_user_name(criteria)
else
# No query? Return all records, sorted by hierarchy.
order( :updated_at )
end
end
# Allow user creation when a new one comes through OmniAuth
def self.from_omniauth(auth)
where(provider: auth.provider, email: auth.info.email).first_or_create do |user|
user.login = auth.info.email
user.uuid = auth.uid
user.provider = auth.provider
user.email = auth.info.email
user.password = "Odq!1#{Devise.friendly_token[0, 20]}"
user.password_confirmation = user.password
user.first_name = auth.info.first_name
user.last_name = auth.info.last_name
user.name = auth.info.name # assuming the user model has a name
user.user_name = auth.info.email[0, 32]
user.playground_id = 0
user.current_playground_id = 0
user.organisation_id = Parameter.find_by_code("ORGANISATION_ID").property.to_i || 0
user.language = 'fr_OFS'
user.description = 'Created through OmniAuth'
user.active_from = Time.now
user.active_to = Time.now + 3.years
user.is_admin = false
user.is_active = true
user.owner_id = 1
user.created_by = 'OmniAuth'
user.created_at = Time.now
user.updated_by = 'OmniAuth'
user.updated_at = Time.now
user.confirmed_at = Time.now
# If you are using confirmable and the provider(s) you use validate emails,
# uncomment the line below to skip the confirmation emails.
user.skip_confirmation!
end
end
### private functions definitions
private
### before filters
def email_format
self.email = email.downcase
end
def name_update
self.name = "#{first_name} #{last_name}"
end
def self.find_for_database_authentication(warden_conditions)
conditions = warden_conditions.dup
if login = conditions.delete(:login)
where(conditions.to_h).where(["lower(user_name) = :value OR lower(email) = :value", { :value => login.downcase }]).first
elsif conditions.has_key?(:user_name) || conditions.has_key?(:email)
where(conditions.to_h).first
end
end
def member_of_Everyone_group
errors.add(:base, :EveryoneMembershipMissing) unless group_ids.include? 0
end
end

validate only on some method rails

Based on rails validation docs. I need to validate fullname field only on update
# encoding: utf-8
class User < ActiveRecord::Base
GENDER_MALE = true
GENDER_FEMALE = false
attr_accessor :password_confirm,
:term,
:year, :month, :day,
:captcha
validates :username, presence: {message: "Bạn phải nhập tài khoản"},
uniqueness: {message: 'Tài khoản đã tồn tại'}, :on => :update
# validates :password, presence: {message: "Bạn phải nhập mật khẩu"},
# confirmation: {message: 'Mật khẩu không chính xác'}
# validates :password_confirmation, presence: {message: "Bạn phải nhập xác nhận mật khẩu"}
# validates :fullname, presence: {message: "Bạn phải nhập họ tên"}
# validates :email, presence: {message: "Bạn phải nhập email"},
# uniqueness: {message: "Email đã tồn tại"}
# validates :email, format: {with: /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i, message: "Email không đúng định dạng"},
# unless: "email.blank?"
# validates :term, acceptance: {message: "Bạn phải đồng ý điều khoản"}
# # validates :gender, acceptance: {accept: [0,1], message: "Giới tính không hợp lệ"}
# validate :_birthday_validator
# validate :_captcha_validator
#
# before_save :_encrypt_password
def signup
self.birthday = "#{year.to_s}-#{month.to_s}-#{day.to_s}"
self.save
end
def self.human_attribute_name(attr, option = {})
"" || super
end
protected
def _encrypt_password
self.password = Digest::MD5::hexdigest(password)
end
private
def _birthday_validator
unless year.present? && month.present? && day.present?
errors.add(:birthday, 'Bạn phải nhập ngày sinh')
else
errors.add(:birthday, 'Ngày sinh không hợp lệ') unless Date.valid_date?(year.to_i, month.to_i, day.to_i)
end
end
def _captcha_validator
if !(captcha.nil?)
errors.add(:captcha, "Mã xác nhận không hợp lệ") if captcha == false
end
end
end
As understand, this validation rule only run when I call update method, but I have no idea why this rule run all the time
Can anyone tell me why or I missed somethings?
Ps: Can Rails validates only for user defined method, somethings like
validates :username, presence: true, only: [:my_func]
One way would be to set a virtual attribute which you'll only populate in the signup method:
#app/models/user.rb
class User < ActiveRecord::Base
attr_accessor :should_validate
validates :fullname, presence: true, on: :update, if: "should_validate.present?"
end
This way, you can then assign a value to should_validate only when you use signup:
def signup
self.birthday = "#{year.to_s}-#{month.to_s}-#{day.to_s}"
self.should_validate = true
self.save
end
you can use method like
validate :fullname , on: :update
def fullname
if self.fullname.present?
true
else
false
end
end

Rails Change record values

I have a record in postgresql of user status it is boolean and its attributes are "true" and "false". I want to show "true" as "active and "false" as "inactive". How do I do it with query or any thing to add in model.
Controller:
def index
#users = User.reorder("id ASC").page(params[:page]).per_page(10)
#count = 0
end
Model:
class User < ActiveRecord::Base
has_many :orders
has_many :order_statuses
attr_accessible :first_name, :last_name, :email, :password,
:password_confirmation, :code
validates :first_name, presence: true
validates :last_name, presence: true
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-]+(\.[a-z]+)*\.[a-z]+\z/i
validates :email, presence: true, format: { with: VALID_EMAIL_REGEX }, uniqueness: { case_sensitive: false }
validates :password, length: { minimum: 6}
has_secure_password
before_save { self.email = email.downcase }
before_create :create_remember_token
def User.new_remember_token
SecureRandom.urlsafe_base64
end
def User.encrypt(token)
Digest::SHA1.hexdigest(token.to_s)
end
private
def create_remember_token
self.remember_token = User.encrypt(User.new_remember_token)
end
end
Add this method in your model, and when you call #user.status, it will show 'Active' or "Inactive".
def status
self.status? ? "Active" : "Inactive"
end
Hope, It will help. Thanks
If I understand you correctly you want to display to your users "active" instead of true and "inactive" instead of false.
You could do something like this in all your views:
#user.status? ? 'active' : 'inactive'
Or if you need this in a bunch of places you could write a helper:
module UserHelper
def status_text(user)
#user.status? ? 'active' : 'inactive'
end
end
# and call it from your views like this:
<%= status_text(#user) %>
Or you could put that into a model method if you need this function only in conjunction with the user and it's active method (as per Rails Guy's suggestion)
Lastly you could use I18n to translate the string for you if you have a mulitlingual page:
# en.yml
en:
status:
true: 'active'
false: 'inactive'
# user_helper.rb
def status_text(user)
I18n.t("statys.#{user.status.to_s}")
end

Validates doesn't work?

i am new in ruby and like the syntax! But i keep getting this error, can someone tell me why? I did also try to include it with include ActiveModel::Validations without any luck. Getting this "stack level too deep"
class HomeController < ApplicationController
def index
if params[:username]
l = Users.new(:username => params[:username], :password => params[:password], :email => params[:email]).save
z = Users.where(:username => params[:username]).limit(1).last
#debugging = "Howdy" + z[:username] + ""
end
end
end
users model:
class Users < ActiveRecord::Base
validates :username, :presence => true
attr_accessible :email, :password, :username
end
It should be in your model if you are using active record:
validates :username, :presence => true
It should be User < ActiveRecord::Base:
user.rb
class User < ActiveRecord::Base
validates :username, :presence => true #or you can also write as 'validates_presence_of :username'
attr_accessible :email, :password, :username
end
home_controller.rb
class HomeController < ApplicationController
def index
if params[:username]
l = User.new(:username => params[:username], :password => params[:password], :email => params[:email])
if l.save?
flash[:success] = "Valid user"
else
flash[:error] = "Invalid user"
end
z = User.where(:username => params[:username]).limit(1).last
#debugging = "Howdy" + z[:username] + ""
end
end
end
Your model seems ok
Try to change your index action for this:
if params[:username]
user = User.create(:username => params[:username], :password => params[:password], :email => params[:email])
if user.persisted?
#debugging = "Howdy #{user.username}"
else
#debugging = "Error while creating user"
end
end
If the user is not valid User.create will create an User object not persisted in database

Generate reset password token don't save on model

Hello I trying to create a reset password for my rails app; but when I try to save I get the following error:
Validation failed: Password can't be blank, Password is too short
(minimum is 6 characters), Password confirmation can't be blank
This is my user model.
class User < ActiveRecord::Base
attr_accessible :email, :password, :password_confirmation
has_secure_password
before_save { |user| user.email = email.downcase }
before_save :create_remember_token
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
def send_password_reset
self.password_reset_token = SecureRandom.urlsafe_base64
self.password_reset_at = Time.zone.now
self.password = self.password
self.password_confirmation = self.password
save!
end
private
def create_remember_token
self.remember_token = SecureRandom.urlsafe_base64
end
end
the method "send_password_reset" doesn't update the user and I don't understand why is trying to save the user instead on updating just password_reset_token and the password_reset_at.
Does anybody can help me, please?
When you call save! on the model instance, it's going to run the validations on your User model; all of them.
There are a number of ways to skip the password validations conditionally. One is to use a Proc
validates :password, presence: true, length: { minimum: 6 }, unless: Proc.new { |a| !a.new_record? && a.password.blank? }
This will allow the User instance to be saved and will skip the validation of the :password field if it's blank and the User is not new (already persisted to the database).
Here is most of a password validation I use in my applications
validates :password, confirmation: true,
length: {:within => 6..40},
format: {:with => /^(?=.*\d)(?=.*([a-z]|[A-Z]))([\x20-\x7E]){6,40}$/},
Notice, you don't need the separate validation on :password_confirmation. Instead just pass confirmation: true to the :password validator.
Suggested Reading:
http://guides.rubyonrails.org/active_record_validations_callbacks.html#confirmation

Resources