Choosing which form field to submit - ruby-on-rails

I have a CommercialDocument model which have a discount_amount attribute and a discount_amount_with_tax virtual attribute.
Here is how I defined this in my model :
def discount_amount_with_tax
discount_amount * (1 + tax.rate / 100)
end
def discount_amount_with_tax=(amount)
self.discount_amount = amount.to_f / (1 + tax.rate / 100)
end
In my form, a user can fill in both discount_amount and discount_amount_tax :
= f.label :discount_amount
= f.text_field :discount_amount
= f.text_field :discount_amount_with_tax
I want to give the priority to the discount_amount_with_tax field, which means that discount_amount must not be taken into account unless the other field is empty.
My problem is that if I put nothing in the discount_amount_with_tax field, and let's say 10 in discount_amount, then discount_amount will be equal to 0, which is clearly not what I want.
How can I fix this ?
Any help would be greatly appreciated.

"".to_i
# => 0
A blank string converts to a zero integer. Therefore:
def discount_amount_with_tax=(amount)
self.discount_amount = amount.to_f / (1 + tax.rate / 100)
end
# same as...
def discount_amount_with_tax=(0)
self.discount_amount = 0 / (...)
end
# 0 / anything except zero = 0
# self.discount_amount = 0 no matter what
During mass-assignment, discount_amount_with_tax= is called. A blank form input is passed as an empty string, which Active Record then converts to an integer (zero). discount_amount_with_tax= sets discount_amount to zero regardless of discount_amount's previous value.
Easy way around this is to use a conditional:
def discount_amount_with_tax=(amount)
self.discount_amount = (amount.to_f / (1 + tax.rate / 100)) if amount > 0
end
Mind you, this is the easy way, not the ideal way. A better solution is to write custom setter logic in the controller in lieu of mass-assignment; basically to manually set these attributes in the controller.

I think you can use a before_validation callback here to set the discount_amount field.
before_validation :calculate_discount_amount
def discount_amount_with_tax
#discount_amount_with_tax ||= discount_amount * (1 + tax.rate / 100.0)
end
def discount_amount_with_tax=(amt)
#discount_amount_with_tax = amt
end
def calculate_discount_amount
self.discount_amount = discount_amount_with_tax / (1 + tax.rate / 100.0)
end
Just a reminder that you need to use 100.0 instead of 100 so that you'll be dividing by float and not by integer.

Related

Calculation Logic In Rails App

I have an rails app wherein I need to pick up data from user through UI store them in a DB which I am able to do without any hiccups. However I need to retrieve the stored data from DB and perform some calculations over them and then plot them using a graph library.
I read that calculation logic generally belongs to the model, hence my model file code is listed as below. But now I am wondering as to how to pass my resultant arrays to an view and get it plotted. Basically I am not getting the interconnection right. Any help on this would be much appreciated.
class Shot < ActiveRecord::Base
def self.calculate(param)
#fetch_all_three_shots
#Performs Query aginst DB and returns the same data structure depicted in 'shots' array
#shots = Shot.all.collect{|a| [a.c1,a.c2,a.c3,a.c4,a.c5,a.c6,a.c7,a.c8,a.c9,a.c10,a.c11,a.c12]}
#shots = [[1.55, 1.58, 1.59, 1.58, 1.53, 1.57, 1.57, 1.55, 1.57, 1.6, 1.62, 1.6],
# [1.54, 1.55, 1.58, 1.57, 1.49, 1.56, 1.55, 1.55, 1.54, 1.59, 1.61, 1.6],
# [1.55, 1.57, 1.59, 1.57, 1.51, 1.56, 1.56, 1.55, 1.56, 1.59, 1.62, 1.59]]
shots = fetch_all_three_shots
#Declaration of Array for all Data Sets Goes here...
cavity_arr = Array.new
avgpartwt_arr = Array.new
fillseq_arr = Array.new
imbalance_arr = Array.new
max_imbalance_arr = Array.new
intermediate_arr = Array.new
fillmeanwt_arr = Array.new
statistics_shotwise_arr = Array.new
statistics_bof_arr = Array.new
#Formulation of Cavity Array Goes Here...
cavity_arr = (1 .. 12).to_a
#Looping for Calculation of Average Part Weight Goes Here...
for i in (0 .. (shots[0].size - 1))
avgpartwt_arr.push((shots[0][i] + shots[1][i] + shots[2][i]) / 3)
end
#Rank Calculation Logic Goes Here....
fillseq_arr = avgpartwt_arr.map{|value| avgpartwt_arr.select{|item| item > value}.size + 1}
#Looping for Calculation of Percentage Imbalance Goes Here...
for i in (0 .. (avgpartwt_arr.size - 1))
imbalance_arr.push(((avgpartwt_arr.max - avgpartwt_arr[i]) / avgpartwt_arr.max) * 100)
end
#Looping for Maximum Imbalance Array Goes Here...
for i in (0 .. (imbalance_arr.size - 1))
if imbalance_arr[i] != imbalance_arr.max
max_imbalance_arr.push(0)
else
max_imbalance_arr.push(cavity_arr[i])
end
end
#Formulation of Intermediate Array Goes Here...
intermediate_arr = [((avgpartwt_arr.mean).round(3))] * 12
#Formulation of Fill Weight Mean Array Goes Here...
for i in (0 .. (avgpartwt_arr.size - 1))
fillmeanwt_arr.push(((intermediate_arr[i] - avgpartwt_arr[i]) / intermediate_arr[i]) * 100)
end
#Looping for Calculation of Shotwise Statistical Parameters Across Shots Goes Here...
for i in (0 .. (shots.size - 1))
statistics_shotwise_arr.push( [shots[i].max, shots[i].min, shots[i].range, shots[i].mean, shots[i].standard_deviation] )
end
#Formulation of Balance of Fill Parameters Goes Here...
cavmaximbalance = max_imbalance_arr.max
maximbalance = imbalance_arr.max
avgimbalance = imbalance_arr.mean
rangedrop = (((statistics_shotwise_arr[0][2] - statistics_shotwise_arr[2][2]) / statistics_shotwise_arr[0][2]) * 100)
end
scope :fetch_all_three_shots , -> {all.collect{|a| [a.c1, a.c2, a.c3, a.c4, a.c5 ,a.c6, a.c7, a.c8, a.c9, a.c10, a.c11, a.c12]}}
end
You could try the following:
class SomeController < ApplicationController
def some_action
#some_variable = Shot.calculate(params)
render :show_action
end
end
#some_variable, which is the return value of the Shot.calculate(params), is available in the view.

How can I divide two table fields?

This is in my model:
before_save :set_pay_this
def set_pay_this
self.pay_this = "#{self.amount} / #{self.divisor}"
end
end
But what gets saved as "pay this" is the "amount" entry, so no division is being done. Is it my syntax or what else should I post to ask my question properly?
"#{self.amount} / #{self.divisor}" is a string. If amount was 5 and divisor was 2 you'd end up with "5 / 2" the string, not the mathematical equation. You want this:
self.pay_this = self.amount / self.divisor
Or maybe this if you care about the cents and amount and divisor are integers.
self.pay_this = self.amount.to_f / self.divisor

Repeating same block of code over an ActiveRecord Object's attributes in Ruby (Rails)

I have a basic function which takes in different values for weight and reps for a barbell lift, and converts it to an estimated one rep max, which gets stored in my database. Here is what the code currently looks like:
if deadlift_reps != 1
self.deadlift = deadlift_wt * deadlift_reps * 0.0333 + deadlift_wt
else
self.deadlift = deadlift_wt
end
if squat_reps != 1
self.squat = squat_wt * squat_reps * 0.0333 + squat_wt
else
self.squat = squat_wt
end
if benchpress_reps != 1
self.benchpress = benchpress_wt * benchpress_reps * 0.0333 + benchpress_wt
else
self.benchpress = benchpress_wt
end
if overheadpress_reps != 1
self.overheadpress = overheadpress_wt * overheadpress_reps * 0.0333 + overheadpress_wt
else
self.overheadpress = overheadpress_wt
end
I am obviously repeating myself a lot in this code block, but cannot figure out how to break it out and interpolate the method names. I've tried using an array with
lifts = [deadlift, squat, benchpress, overheadpress]
But when I try using each do on this to string interpolate, I am getting an error that lifts doesn't have this method.
Can anyone offer me any advice on how to proceed?
edit:
The loop I was trying to do was:
lifts = [deadlift, squat, benchpress, overheadpress]
lifts each do |lift|
if '#{lift}_reps' !=1
self.#{lift} = '#{lift}_wt' * '#{lift}_reps' * 0.0333 + '#{lift}'_wt
else
self.#{lift} = '#{lift}_wt'
end
end
I can see why this isn't working, but, using a similar idea, how would I make it work?
I would create a private method to calculate every piece of:
if deadlift_reps != 1
...
end
and assign the values to different fields (deadlift, squat, benchpress, overheadpress) using the assign_attributes Active record methods.
Here is the code, I didn't test it, but it should work:
[["deadlift", 20, 8],
["squat", 10, 12],
["benchpress", 30, 6],
["overheadpress", 20, 10]]).each do |exercize, wt, reps|
set_exercize(exercize, wt, reps)
end
private
def set_exercize(exercize, wt, reps)
value = reps != 1 ? wt * reps * 0.0333 + wt : wt
self.assign_attributes(exercize => value)
end
I hope it can help you.

How to get net salary value from database in rails 4

I am having problem getting net-salary value. I have teacher_payslip model. For calculating net-salary,I have written callback.
In TeacherPayslip.rb
#callbacks
after_create :net_salary
def net_salary
#teacher_id = self.id
#da = (self.basic * self.da)/100
#hra = (self.basic * self.hra)/100
#gs = #da + #hra + self.basic
#pf = (#gs * self.pf)/100
#netsalary = #gs - #pf + self.special_allowance + self.bonus
#raise #netsalary.inspect
#a = TeacherPayslip.find(#teacher_id)
#raise #a.inspect
#a.update_attributes(:net_salary => #netsalary)
end
The net_salary value was updated in TeacherPayslip Model.
In Rails console, I have tried some code
TeacherPayslip.last.net_salary
Shows true value instead of net_salary value
I don't know, Why this query shows true value.. Please Help Me...
It's a naming collision. You're overwriting the method net_salary.
The return value of true is the return value of update_attributes.
To fix this rename your method and the callback to set_net_salary.
user it
TeacherPayslip.last.net_salary

Return the value if the value exists

In Ruby on Rails, is there a better way to write this:
qty = 2
avg_price = room["price"].to_f if room["price"].present?
total_price = (avg_price * qty) if avg_price.present?
Especially the 2nd and 3rd line. I find myself using the if-else condition too often. Thanks.
You can try something like this:
qty = 2
total_price = room.fetch("price").to_f * qty
But there is a problem with this code, if there is no price field in the hash, it will raise an exception. Does it suffice your needs ?
It is hard to make this shorter, I would just do:
qty, avg_price, total_price = 2, nil, nil
if room["price"]
avg_price = Float(room["price"])
total_price = avg_price * qty
end
What about defining a helper method so that you can directly extract a float from a hash:
class Hash
def get_f key; fetch(key).to_f if key?(key) end # Or `if self[key].present?`
end
and then do:
qty = 2
avg_price = room.get_f("price")
total_price = avg_price * qty if avg_price
Perhaps a more object oriented approach? This approach makes it easier to test the code and might be reuseable.
class PriceCalculator
def init(quantity, price)
#quantity = quantity
#price = price.presence && price.to_f
end
def total
#price * #quantity if #price
end
end
total_price = PriceCalculator.new(2, room["price"]).total

Resources