I am using barby gem to generate gs1-128 barcode. I am able to save the barcode in a .png file. Below is the code i am using,
def pti_label_preview
gtin_no = params[:gtin_no]
barcode = Barby::GS1128.new(gtin_no,'C','12')
full_path = "#{Rails.root}/public/uploads/barcode.svg"
File.open(full_path, 'w') { |f| f.write barcode.to_svg(:margin => 3, :xdim => 2, :height => 55) }
render :text => path
end
I created it by referring this. Barby::GS1128.new(gtin_no,'C','12') is accepting 3 argument, i want to know what are the 3 values i have to send to create barcode.
I have following values gs1_prefix, item no, check sum value, gtin no, lot no etc. What are the 3 values should i pass to GS1128 method
You can pull the repo of that gem down and find this.
class GS1128 < Code128
def initialize(data, type, ai)
self.application_identifier = ai
super(data, type)
end
...
end
So the answer to your question is the 3 arguments you pass are data, type and ai
Related
I want to use a transformed name/value in the property of a class than we get from the database. The reason I need this is I have two versions of an app that points to the same database, but the newer version recently updated the column name. So, for all apps that use the older version it has to be made compatible.
Environment: Rails version: 6.0.3.3 & Ruby version: ruby 2.7.1p83
Suppose there is class called Sprinter.
Sprinter table looks like:
id
name
m
s
1
Mr. Bolt
100
9.58
A sprinter instance would look like:
sprinter = {
"id" => 1,
"name" => "Mr. Bolt",
"m" => 100,
"s" => 9.58
}
The older version expects a different format. Now I want to have something like:
sprinter = {
"id" => 1,
"name" => "Mr. Bolt",
"cm" => 10000, # transformed from `m`
"ms" => 9580 # transformed from `s`
}
The m column name has been transformed to cm and the value has been transformed too. Same case for s to ms. The value transformation is not a big deal, but the variable name seems to be.
I'd prefer an internal update when I fetch the object. However if that's not supported, as a base-level solution, I'd prefer to change the json representation that I sent to the client. For reference, I use it as part of nested include like:
render status: :ok, json: {races: races}.as_json(
{:include => [:sprinters] }
)
Thanks.
Instead of mucking about with the internals of .as_json or how your model does serialization you can use a serialization layer instead to handle different representations of your model in JSON.
For example you can use ActiveModel::Serializers or JBuilder or even roll your own if thats your deal.
module API
module V2
class SprinterAdapter
def intialize(sprinter)
#sprinter = sprinter
end
def to_json
#sprinter.to_json.except("m", "s").merge(
"cm" => #sprinter.m * 100,
"ms" => #sprinter.s * 1000
)
end
end
end
end
And in your controller you would use the serializer to render the resource:
module API
module V2
class SprintersController < ApplicationController
def show
#sprinter = Sprinter.find(params[:id])
render json: SprinterAdapter.new(#sprinter)
end
end
end
end
See:
Thoughtbot: Better serialization, less as_json
Ruby Toolbox
You could transform keys/values by select from Sprinter:
Sprinter.select(:id, :name, 'm * 100 AS cm', 's * 1000 AS ms')
But not sure how to combine it with as_json
I want it to be able to read in JSON and save it correctly regardless whether the value is 44.5, 44 or 44.99. The price attributes are a decimal format.
The error is happening in the convert_price method. The price in the JSON response can be 44, 44.50 or 44.99. However, I noticed that sometimes the last decimal is cut off, like in the error 44.5.
I'm receiving this error:
undefined method 'match' for float 74.5:Float
My code is:
# read in JSON and create books
def create_item
job_items_url = "https://foobar.com&format=json"
response = open(job_items_url).read.to_s
books = JSON.parse(response)
Book.create(reg_price: convert_price(item['reg_price']),
sale_price: convert_price(item['sale_price']))
end
# format the price
def convert_price(price)
return nil if price.blank? || price.to_f.zero?
price = "#{price}.00" unless price.match(/[,.]\d{2}\z/)
price.delete(',.').to_f / 100
end
You can use number_to_currency without a unit:
>> number_to_currency(45,unit:"")
=> "45.00"
>> number_to_currency(45.5,unit:"")
=> "45.50"
>> number_to_currency(45.55,unit:"")
=> "45.55"
>>
See number_to_currency for more information.
It looks like price is already a Numeric object. Check out sprintf for simple Type-aware padding, for example:
sprintf('%.2f', 44.5) # => "44.50"
# so you should do something like this:
sprintf('%.2f', price.to_f)
A suggestion:
def try_format_currency(price)
sprintf('%.2f', Float(price))
rescue => ex
# log error if you want
nil
end
Use Float() conversion, which can raise, which will clearly express that price is "untrustworthy" input, and might not be a proper number
Express the same thing in the naming of the method
host = Host.find(i)
a = host.open_ports
openPorts = []
a.split(",").each do |x|
openPorts << x
end
This is the set up were talking Ruby on Rails, so I set up my Ip address on iand grab all the open ports.String returned is then broken up via "," and added to an array.
Finding.all.each do |p|
openPorts.each do |y|
if p.port == y
Report.create(:port => p.port,
:risk_rating => p.risk_rating,
:finding => p.finding,
:implication => p.implication,
:recommendation => p.recommendation)
end
end
end
Iterates through findings table in the database and checks if the ports match the open ports array we created above. If there is a match we create a new report, based on the given value from the finding table.
The problem is does not create a new report even if there is a match.
Any help is appreciated.
Not sure if this helps but I wanted to show you how to clean up the implementation a bit.
host = Host.find(i)
# I am assuming Finding#port is an Integer
# if Finding#port is a String then just remove the .map(&:to_i) portion
open_ports = host.open_ports.split(",").map(&:to_i)
Finding.where(port: open_ports).each do |p|
Report.create(:port => p.port,
:risk_rating => p.risk_rating,
:finding => p.finding,
:implication => p.implication,
:recommendation => p.recommendation)
end
Lets start at the top
String#split returns an Array so no need to push it into a new one. It does however create an Array of Strings so if you need integers #map(&:to_i) will do this for you. I am assuming this is the current issue which is comparison of a string with integer for example "80" == 80 #=> false
Next rather than loop through all the Findings why not just pull out the one's with matching ports? Finding.where(port: open_ports) this will generate a query like SELECT findings.* FROM findings where findings.port IN (YOUR_OPEN_PORTS_ARRAY)
Then we just create the reports from this limited list instead of the loop through all Findings and then a loop through open_ports as well.
This question already has answers here:
What does map(&:name) mean in Ruby?
(17 answers)
Closed 8 years ago.
I'm reviewing someone's ruby code and in it they've written something similar to:
class Example
attr_reader :val
def initialize(val)
#val = val
end
end
def trigger
puts self.val
end
anArray = [Example.new(10), Example.new(21)]
anArray.each(&:trigger)
The :trigger means the symbol is taken and the & transforms it into a proc?
If that's correct, is there any way of passing variables into trigger apart from using self.?
This is related but never answered: http://www.ruby-forum.com/topic/198284#863450
is there any way of passing variables into trigger
No.
You're invoking Symbol#to_proc which does not allow you to specify any arguments. This is a convenient bit of sugar Ruby provides specifically for invoking a method with no arguments.
If you want arguments, you'll have to use the full block syntax:
anArray.each do |i|
i.trigger(arguments...)
end
Symbol#to_proc is a shortcut for calling methods without parameters. If you need to pass parameters, use full form.
[100, 200, 300].map(&:to_s) # => ["100", "200", "300"]
[100, 200, 300].map {|i| i.to_s(16) } # => ["64", "c8", "12c"]
This will do exactly what you need:
def trigger(ex)
puts ex.val
end
anArray = [Example.new(10), Example.new(21)]
anArray.each(&method(:trigger))
# 10
# 21
I'm wanting a method called same_url? that will return true if the passed in URLs are equal. The passed in URLs might be either params options hash or strings.
same_url?({:controller => :foo, :action => :bar}, "http://www.example.com/foo/bar") # => true
The Rails Framework helper current_page? seems like a good starting point but I'd like to pass in an arbitrary number of URLs.
As an added bonus It would be good if a hash of params to exclude from the comparison could be passed in. So a method call might look like:
same_url?(projects_path(:page => 2), "projects?page=3", :excluding => :page) # => true
Here's the method (bung it in /lib and require it in environment.rb):
def same_page?(a, b, params_to_exclude = {})
if a.respond_to?(:except) && b.respond_to?(:except)
url_for(a.except(params_to_exclude)) == url_for(b.except(params_to_exclude))
else
url_for(a) == url_for(b)
end
end
If you are on Rails pre-2.0.1, you also need to add the except helper method to Hash:
class Hash
# Usage { :a => 1, :b => 2, :c => 3}.except(:a) -> { :b => 2, :c => 3}
def except(*keys)
self.reject { |k,v|
keys.include? k.to_sym
}
end
end
Later version of Rails (well, ActiveSupport) include except already (credit: Brian Guthrie)
Is this the sort of thing you're after?
def same_url?(one, two)
url_for(one) == url_for(two)
end
def all_urls_same_as_current? *params_for_urls
params_for_urls.map do |a_url_hash|
url_for a_url_hash.except(*exclude_keys)
end.all? do |a_url_str|
a_url_str == request.request_uri
end
end
Wherein:
params_for_urls is an array of hashes of url parameters (each array entry are params to build a url)
exclude_keys is an array of symbols for keys you want to ignore
request.request_uri may not be exactly what you should use, see below.
Then there are all sorts of things you'll want to consider when implementing your version:
do you want to compare the full uri with domain, port and all, or just the path?
if just the path, do you want to still compare arguments passed after the question mark or just those that compose the actual path path?