I want to concatenate two values into a single string - ruby-on-rails

I have two different values systolic and diastolic blood pressure readings in string. When those two values come from front-end I'll store them into a single string, e.g., if systolic ='120' and diastolic='80' I want bp='120/80'
module Api
module V1
module CheckinMachine
class BpsController < ApplicationController
include MachineError
before_action :authenticate_user!
def create
raise BatteryNotFunctionalError if battery_functional?
# user = User.find_by!(bp_machine_imei: params[:imei])
health_reading = current.health_readings.create!(key: :blood_pressure, value: bp_value)
Solera::PostActivityApi.call(user,
bp,
health_reading.solera_activities.new)
head :ok
rescue ActiveRecord::RecordNotFound => _e
render_machine_error and return
end
def show
puts params
end
private
def bp
{
systolic_blood_pressure: params[:systolic],
diastolic_blood_pressure: params[:diastolic]
}
end
end
end
end
end
That's what i have tried, what do i do to make it exactly like i want it to be
like bp = '120/80'

Since you already have the 2 values stored in params, this is super easy:
bp = " #{params[:systolic] / #{params[:diastolic]} "
> bp = " 120/80 "
Remember that Ruby has the variable substitution in strings using the #{x} syntax where x is a variable value.
So for instance:
x = "apples"
y = 5
string = "I have #{y} units of #{x} to sell you"
puts(string)
> "I have 5 units of apples to sell you"

Related

wrong number of arguments (given 0, expected 4)

I am getting this error for this set up. My thought is that the file cannot properly access the csv. That I am attempting to import. I've got to import from one csv to create another csv using the model date. What do I put in the controller and views to show the new csv / manipulated data? Basically how can I pass one csv file in a model for manipulation (orders.csv) and out into another csv file (redemption.csv) the code in the model is just telling model to calculate the existing numbers in orders.csv a certain way for export without this argument error?
The controller (I don't really know what to do here)
class OrdersController < ApplicationController
def index
orders = Order.new
end
def redemptions
orders = Order.new
end
end
The View (not confident about this either)
<h1>Chocolates</h1>
puts "#{order.purchased_chocolate_count}"
<%= link_to "CSV", orders_redemptions_path, :format => :csv %>
Model
require 'csv'
# Define an Order class to make it easier to store / calculate chocolate tallies
class Order < ActiveRecord::Base
module ChocolateTypes
MILK = 'milk'
DARK = 'dark'
WHITE = 'white'
SUGARFREE = 'sugar free'
end
BonusChocolateTypes = {
ChocolateTypes::MILK => [ChocolateTypes::MILK, ChocolateTypes::SUGARFREE],
ChocolateTypes::DARK => [ChocolateTypes::DARK],
ChocolateTypes::WHITE => [ChocolateTypes::WHITE, ChocolateTypes::SUGARFREE],
ChocolateTypes::SUGARFREE => [ChocolateTypes::SUGARFREE, ChocolateTypes::DARK]
}
# Ruby has this wacky thing called attr_reader that defines the available
# operations that can be performed on class member variables from outside:
attr_reader :order_value
attr_reader :chocolate_price
attr_reader :required_wrapper_count
attr_reader :order_chocolate_type
attr_reader :chocolate_counts
def initialize(order_value, chocolate_price, required_wrapper_count, order_chocolate_type)
#order_value = order_value
#chocolate_price = chocolate_price
#required_wrapper_count = required_wrapper_count
#order_chocolate_type = order_chocolate_type
# Initialize a new hash to store the chocolate counts by chocolate type.
# Set the default value for each chocolate type to 0
#chocolate_counts = Hash.new(0);
process
end
# Return the number of chocolates purchased
def purchased_chocolate_count
# In Ruby, division of two integer values returns an integer value,
# so you don't have to floor the result explicitly
order_value / chocolate_price
end
# Return the number of chocolate bonuses to award (which can include
# multiple different chocolate types; see BonusChocolateTypes above)
def bonus_chocolate_count
(purchased_chocolate_count / required_wrapper_count).to_i
end
# Process the order:
# 1. Add chocolate counts to the totals hash for the specified order type
# 2. Add the bonus chocolate types awarded for this order
def process
chocolate_counts[order_chocolate_type] += purchased_chocolate_count
bonus_chocolate_count.times do |i|
BonusChocolateTypes[order_chocolate_type].each do |bonus_chocolate_type|
chocolate_counts[bonus_chocolate_type] += 1
end
end
end
# Output the chocolate counts (including bonuses) for the order as an array
# of strings suitable for piping to an output CSV
def csv_data
ChocolateTypes.constants.map do |output_chocolate_type|
# Get the display string (lowercase)
chocolate_key = ChocolateTypes.const_get(output_chocolate_type)
chocolate_count = chocolate_counts[chocolate_key].to_i
"#{chocolate_key} #{chocolate_count}"
end
end
end
# Create a file handle to the output file
CSV.open("redemptions.csv", "wb") do |redemption_csv|
# Read in the input file and store it as an array of lines
input_lines = CSV.read("orders.csv")
# Remove the first line from the input file (it just contains the CSV headers)
input_lines.shift()
input_lines.each do |input_line|
order_value, chocolate_price, required_wrapper_count, chocolate_type = input_line
# Correct the input values to the correct types
order_value = order_value.to_f
chocolate_price = chocolate_price.to_f
required_wrapper_count = required_wrapper_count.to_i
# Sanitize the chocolate type from the input line so that it doesn't
# include any quotes or leading / trailing whitespace
chocolate_type = chocolate_type.gsub(/[']/, '').strip
order = Order.new(order_value, chocolate_price, required_wrapper_count, chocolate_type)
order.process()
puts order.purchased_chocolate_count
# Append the order to the output file as a new CSV line
output_csv << order.csv_data
end
end
In Your initialize method you are not provide default value to argument.
def initialize(order_value, chocolate_price, required_wrapper_count, order_chocolate_type)
When you are trying to run orders = Order.new it is expecting four argument and you haven't provide it.
One more issue. Your local variable name should be order not orders for proper naming convention.
To assign default values properly, you can look here.

Array not saving user input in ruby

This is what I have so far, but the array is not saving the first value if the user enters 2 or more car types. If I remove the car.get_ methods the program runs fine without saving the users input. Is there a method I am missing?
class Cars
def set_make(make)
end
def set_model(model)
end
def set_year(year)
end
array_of_cars = Array.new
print "How many cars do you want to create? "
num_cars = gets.to_i
puts
for i in 1.. num_cars
puts
print "Enter make for car #{i}: "
make = gets.chomp
print "Enter model for car #{i}: "
model = gets.chomp
print "Enter year of car #{i}: "
year = gets.to_i
c = Car.new
c.set_make(make)
c.set_model(model)
c.set_year(year)
array_of_cars << c
end
puts
puts "You have the following cars: "
for car in array_of_cars
print "#{car.get_year} #{car.get_make} #{car.get_model}"
end
end
Ok so the primary issue is that you calling the Car.new where the Car class is defined. You should not have an array of cars in the car class. You could try creating a Dealership class that has an array of cars then you could do something like this
class Dealership
attr_accessor :car_lot
def initialize
#car_lot = []
end
def add_car(car)
#car_lot << car
end
end
crazy_carls = Dealership.new
car1 = Car.new(make, model, year)
crazy_carls.add_car(car1)
crazy_carls.car_lot.each do |car
print "#{car.get_year} #{car.get_make} #{car.get_model}"
end
You need to refactor the car class a good deal first though, look into how to use the initialize method, attr_accessor, and instance variables.

Ruby loops and classes; splitting a string into an array and back to a string again

Ruby newbie here working on loops with classes. I was supposed create a method that would take a string and add exclamation points to the end of each word (by making it an array with .split) and join the 'exclaimed' words as a string again. I've been at this for two hours already and decided I should seek help. I have a handful of ideas but I keep coming up with a NoMethod error. Below is one of ways that made sense to me but of course, it doesn't work. I've also added specs at the very end.
class StringModifier
attr_accessor :string
def initialize(string)
#string = string
end
def proclaim
new_array = []
string.split.each do |word|
new array = "#{word}!"
new_array.join
end
new_array
end
end
SPECS
describe StringModifier do
describe "#proclaim" do
it "adds an exclamation mark after each word" do
blitzkrieg_bop = StringModifier.new("Hey ho let's go").proclaim
expect(blitzkrieg_bop).to eq("Hey! ho! let's! go!")
end
end
end
Write your method as:
def proclaim
string.split.map { |word| "#{word}!" }.join(" ")
end
Or write it as :
def proclaim
a = string.split
("%s! " * a.size % a).strip
end
Tested :
[30] pry(main)> a = "Hey ho let's go".split
=> ["Hey", "ho", "let's", "go"]
[31] pry(main)> ("%s! " * a.size % a).strip
=> "Hey! ho! let's! go!"
[32] pry(main)>

return result back to view

i am trying to keep all my logic out of views, and have come up with the following piece of code, the though im having is that it isnt returning the actual score value, it just returns if it was a Win, lost or tie
def find_result(schedule)
return "not required" if schedule.event != '1' or schedule.time >= Time.now
if schedule.for.nil? or schedule.against.nil?
"Not Entered"
else
tie = '<b>T</b> '
tie << schedule.for.to_i
tie << ' - '
tie << schedule.against.to_i
win = '<b>W</b> '
win << schedule.for.to_i
win << ' - '
win << schedule.against.to_i
return raw tie if schedule.for.to_i == schedule.against.to_i
schedule.for.to_i > schedule.against.to_i ? (raw win) : "Lost"
end
end
Don't use << with an integer. See the docs:
http://www.ruby-doc.org/core-1.9.3/String.html#method-i-3C-3C
It's probably turning your win/loss numbers into characters that aren't showing up in the HTML.
Use a formatter or something, or perhaps just to_s rather than to_i when appending the numbers.
Example using string format (untested):
def find_result(schedule)
return "not required" if schedule.event != '1' or schedule.time >= Time.now
if schedule.for.nil? or schedule.against.nil?
"Not Entered"
elsif schedule.for.to_i < schedule.against.to_i
"Lost"
else
raw "<b>%s</b> %d - %d" % [
schedule.for.to_i == schedule.against.to_i ? 'T' : 'W',
schedule.against.to_i,
schedule.for.to_i
]
end
Edit: Refactor
Keeping logic out of the views is good, but it would be even more appropriate to
move some of this to the model, namely the result of the schedule (not entered,
win, loss, tie)
In the example I'll make a simple inner class which encapsulates that logic, which
the Schedule makes use of to know its own result. You could do this any number of ways
though (e.g. a module versus a class, or methods directly on Schedule)
I'll then demonstrate how you might use the new schedule in your helper using the logic provided, or simply querying for the result itself and using it as a key for a translation lookup (I18n).
Note this is untested and a little bit pseudo-codey (I'm not using any I18n library in particular, just guessing at methods and translation formatting). But it should work with some tweaking, or at least give you an idea of another way of doing things.
class Schedule
# The schedule jus instantiates a result object when you ask for one.
# For convenience the result's to_s is it's value, e.g. "win"
def result
Result.new(self.for, self.against)
end
# delegate methods querying the result
delegate :win?, :loss?, :tie?, :not_entered?, :to => :result
class Result
Values = %(win loss tie not_entered)
Win = Values[0]
Loss = Values[1]
Tie = Values[2]
NotEntered = Values[3]
attr_reader :for, :against
def initialize(_for, against)
#for = _for
#against = against
end
def value
return NotEntered unless [#for, #against].all?
case v = #for - #against
when v.zero? then Tie
when v > 0 then Win
else Loss
end
end
alias :to_s :value
def not_entered?; self.value == NotEntered end
def win?; self.value == Win end
def loss?; self.value == Loss end
def tie?; self.value == Tie end
end
end
# then in your helper, something like
def find_result(schedule)
# you'd want to refactor this requirement part too
return "not required" if schedule.event != '1' or schedule.time >= Time.now
# Now you could do it essentially the way you had, with ifs or a
# case statement or what have you, but the logic for the result is kept
# where it belongs, on the class.
if schedule.not_entered?
"Not Entered"
elsif schedule.loss?
"Loss"
else
prefix = schedule.win? ? "W" : "T"
raw "<b>%s</b> %d - %d" % [prefix, schedule.for, schedule.against]
end
# OR you could use some kind of translation library using the `value`
# returned by the result. Something like:
key = ["schedule", schedule.outcome.value].join(".")
raw I18n.translate(key, {:for => schedule.for, :against => schedule.against})
end
# if you used the latter, it would lookup the translation in some other place,
# e.g. some config JSON, which might look like this (more or less, and
# depending on the lib you use):
{
"schedule": {
"win": "<b>W</b> {{for}} - {{against}}",
"tie": "<b>T</b> {{for}} - {{against}}",
"loss": "Loss",
"not_entered": "Not Entered"
}
}
# The translation has a few advantages. It would allow you to sub in other
# languages, but also, it conveniently keeps all of the app's text in one
# place, if you stick to using it.

How to format values before saving to database in rails 3

I have a User model with Profit field. Profit field is a DECIMAL (11,0) type. I have a masked input on the form which allows user to input something like $1,000. I want to format that value and remove everything except numbers from it so i will have 1000 saved. Here is what i have so far:
class User < ActiveRecord::Base
before_save :format_values
private
def format_values
self.profit.to_s.delete!('^0-9') unless self.profit.nil?
end
end
But it keeps saving 0 in database. Looks like it is converting it to decimal before my formatting function.
Try this:
def profit=(new_profit)
self[:profit] = new_profit.gsub(/[^0-9]/, '')
end
First of all, this:
def format_values
self.profit.to_s.delete!('^0-9') unless self.profit.nil?
end
is pretty much the same as this:
def format_values
return if(self.profit.nil?)
p = self.profit
s = p.to_s
s.delete!('^0-9')
end
So there's no reason to expect your format_values method to have any effect whatsoever on self.profit.
You could of course change format_values to assign the processed string to self.profit but that won't help because your cleansing logic is in the wrong place and it will be executed after '$1,000' has been turned into a zero.
When you assign a value to a property, ActiveRecord will apply some type conversions along the way. What happens when you try to convert '$1,000' to a number? You get zero of course. You can watch this happening if you play around in the console:
> a = M.find(id)
> puts a.some_number
11
> a.some_number = 'pancakes'
=> "pancakes"
> puts a.some_number
0
> a.some_number = '$1,000'
=> "1,000"
> puts a.some_number
0
> a.some_number = '1000'
=> "1000"
> puts a.some_number
1000
So, your data cleanup has to take place before the data goes into the model instance because as soon as AR gets its hands on the value, your '$1,000' will become 0 and all is lost. I'd put the logic in the controller, the controller's job is to mediate between the outside world and the models and data formatting and mangling certainly counts as mediation. So you could have something like this in your controller:
def some_controller
fix_numbers_in(:profit)
# assign from params as usual...
end
private
def fix_numbers_in(*which)
which.select { |p| params.has_key?(p) }.each do |p|
params[p] = params[p].gsub(/\D/, '') # Or whatever works for you
end
end
Then everything would be clean before ActiveRecord gets its grubby little hands on your data and makes a mess of things.
You could do similar things by overriding the profit= method in your model but that's really not the model's job.
class User < ActiveRecord::Base
before_save :format_values
private
def format_values
self.profit = profit.to_s.gsub(/\D/,'') if profit
end
end
def format_values
self.profit.to_d!
end
I recommend you to write custom setter for this particular instance variable #profit:
class User
attr_accessor :profit
def profit= value
#profit = value.gsub(/\D/,'')
end
end
u = User.new
u.profit = "$1,000"
p u.profit # => "1000"
I would suggest using the rails helper of number with precision. Below is some code.
Generic Example:
number_with_precision(111.2345, :precision => 1, :significant => true) # => 100
Rails code Example:
def profit=(new_profit)
number_with_precision(self[:profit], :precision => 1, :significant => true)
end

Resources