Rails Change record values - ruby-on-rails

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

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

Rails NoMethodError for method I did not call

I'm getting the following error
Error Message Image
When trying to save a message object in my MessageController. Here is my controller.
class MessagesController < ApplicationController
def new
#message = Message.new
#user = current_user
end
def create
#message = Message.new(message_params)
#message.user = current_user
#message.user_id = current_user.id
if #message.user_email.nil?
#message.user_email = current_user.email
end
if #message.save
# UserMailer.send_email_to_admin(current_user.email).deliver
else
# redirect_to new_message_path(#message)
end
end
private
def message_params
params.require(:message).permit(:subject, :body, :user_email)
end
end
And here is my model.
class Message < ActiveRecord::Base
belongs_to :user
validates :user_email, presence: true
validates :subject, presence: true, length: { minimum: 5 }
validates :message, presence: true, length: { minimum: 10 }
end
I have no idea why this error is appearing because there are no methods named "message" in my app. Any help would be much appreciated!
In your model you have a validation for the message field:
validates :message, presence: true, length: {minimum: 10}
Is that supposed to be a validation for your body field?:
validates :body, presence: true, length: {minimum: 10}
Before saving the record, the validator is calling the message method on the Message instance(#message) to check its presence and validate it. Since you don't have a column named message but have a validation for it, you will get the NoMethodError.

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

cant sort active records

I am a noobie and I am trying to simply get all the records in the database and display them in alphabetical order. Whenever I display the index page the records are always sorted in descending by their id. I used the console to try calling EvalTest.order("name") and again I kept getting the records sorted by their id in descending order instead of by name. Do I need to add an index on the name column to sort by it? This seems like the answer should be so easy but I can't seem to figure it out...
Here is my code:
User Model:
class User < ActiveRecord::Base
attr_accessible :name, :email, :password, :password_confirmation
has_secure_password
has_many :eval_tests
before_save { |user| user.email = email.downcase }
before_save :create_remember_token
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
after_validation { self.errors.messages.delete(:password_digest) }
private
def create_remember_token
self.remember_token = SecureRandom.urlsafe_base64
end
end
Eval_Test Model:
class EvalTest < ActiveRecord::Base
attr_accessible :description, :name
belongs_to :user
validates :user_id, presence: true
validates :name, presence: true
validates :description, presence: true, length: { maximum: 350 }
default_scope order: 'eval_tests.created_at DESC'
end
EvalTest Controller:
class EvalTestsController < ApplicationController
def show
#eval_test = EvalTest.find(params[:id])
end
def new
#eval_test = EvalTest.new
end
def index
#eval_tests = EvalTest.order("name")
end
def create
#eval_test = current_user.eval_tests.build(params[:eval_test])
if #eval_test.save
flash[:success] = "Nouveau test cree!"
redirect_to #eval_test
else
render 'new'
end
end
end
Evaluation Test index.html.erb:
<% provide(:title, 'Index des tests') %>
<h1>Index des tests</h1>
<ul class="eval_tests">
<% #eval_tests.each do |eval_test| %>
<li>
<%= link_to eval_test.name, eval_test %>
</li>
<% end %>
</ul>
This is happening because you have used default scope in your model. Try
#eval_tests = EvalTest.reorder("name")
This should solve your issue.

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