Convert Class Object to string in Ruby - ruby-on-rails

I m in a situation where i need to convert an Object to string so that i can check for Invalid characters/HTML in any filed of that object.
Here is my function for spam check
def seems_spam?(str)
flag = str.match(/<.*>/m) || str.match(/http/) || str.match(/href=/)
Rails.logger.info "** was spam #{flag}"
flag
end
This method use a string and look for wrong data but i don't know how to convert an object to string and pass to this method. I tried this
#request = Request
spam = seems_spam?(#request.to_s)
Please guide
Thanks

You could try #request.inspect
That will show fields that are publicly accessible
Edit: So are you trying to validate each field on the object?
If so, you could get a hash of field and value pairs and pass each one to your method.
#request.instance_values.each do |field, val|
if seems_spam? val
# handle spam
end
If you're asking about implementing a to_s method, Eugene has answered it.

You need to create "to_s" method inside your Object class, where you will cycle through all fields of the object and collecting them into one string.
It will look something like this:
def to_s
attributes.each_with_object("") do |attribute, result|
result << "#{attribute[1].to_s} "
end
end
attribute variable is an array with name of the field and value of the field - [id, 1]
Calling #object.to_s will result with a string like "100 555-2342 machete " which you can check for spam.

Related

Returning a specific string format from an array

I have an array of Persons (class contain name and lastname and id )
what I have to do is to return a string form this array but in a specific format an example will be more explicative
array=[PERS1,PERS2]
I need this as a return value : "The name of all persons : "+ PERS1.name + PERS1.LASTN + " , " + PERS2.name +PERS2.LASTN +","
I know this method
array.each{ |per|
#but this will not return the format ,and with each I think I can only print (I'm new in the ruby field
}
all of this because I need it when overriding to_s , because I need to provide a string -> to_s
def to_s
"THE name of all preson"+#array.each #will not work as I want
end
Thank you for ur time and effort and if you need any clarification please let me know
each just iterates over a collection and returns the collection itself. You may want to use map and join the result.
array.map { |person| "#{person.name} #{person.lastn}" }.join(',')
Or if you modify your Person class it can be even simpler.
# I assume that the name of the class is Person and name and lastn are always present
class Person
def full_name
"#{person.name} #{person.lastname}"
end
end
# Then you can call this method on `map`.
array.map(&:full_name).join(',')
Try this,
array.each do |per|
"#{per.name} #{per.LASTN}"
end
For more info check Interpolation

Converting array with .join not saving value

I have a method do_stuff that takes a string as a value. However, an array of two strings is occasionally passed in. In this situation, I need to convert the array to a single string (without commas). So for example, ["hello", "world"] should become "hello world".
So, if value = array, join the two strings, otherwise leave it alone.
The following line I have does what I want, but I am struggling with actually "saving" the value before passing it to the method do_other_stuff.
def do_stuff(value)
value.join("") if value.is_a? Array
do_other_stuff(value)
end
So I think i am close, but what would be the best way to ensure value is manipulated before passing it to do_other_stuff ?
join does not change your object, you're wasting its return value
value = value.join if value.is_a? Array
Note that "" is the default for the join parameter, so I got rid of it
Replace
value.join("") if value.is_a? Array
With
value = value.join("") if value.is_a? Array
Basically you need to reassign result back to value
Use duck typing instead of checking the class:
def do_stuff(value)
do_other_stuff(value.try(:join, '') || value)
end
.try is from ActiveSupport and will return nil if the object does not respond to the method. In plain old ruby you would write this as:
def do_stuff(value)
do_other_stuff(value.respond_to?(:join) ? value.join("") : value)
end

Accessing Hash Keys with user inputted variables,Nil value No method error NoMethodError

Hi i had created a small ruby project which consists of JSON file. I stored the JSON data into hash keys. AND worte a method to access the data which is present in hash key using user input. But when i try to send use the user input i am getting this error
how_many_ingredients': undefined methodkeys' for nil:NilClass (NoMethodError)
I found this link with same question and tried that solution but still i'm getting the same error
Accessing Hash Keys with user inputted variables, NoMethodError
File one where all the methods are written
require 'json'
class Methods
attr_accessor :name, :text
def initilize(name)
#name = name
#text = text
end
def how_many_ingredients(text)
puts 'text'
file = File.read('a.json')
hash = JSON.parse(file)
#puts hash['recipes']['pizza'].keys
puts hash['recipes'][text].keys
end
end
File 2 where how_Many_ingredients method is accessed, I can see that the variable is passed to that method
require './1'
class Hello < Methods
person = Methods.new
person.test
puts "enter recipie"
person.name
str = gets
person.how_many_ingredients str
end
Note that when you use gets, the input can contain newline and carriage return characters. You'll need to use gets.chomp to filter these. This is likely the cause of the issue in your program.
Compare the following two:
> puts gets.size
"Hello!"
# 7
> puts gets.chomp.size
"Hello!"
# 6
Note that you'll still need to extend your program to account for user inputted keys that are not in your hash.
Your code assumes that there will always be a hash stored at hash['recipes'][text] - you need to cater to the cases where it isn't.
A simple way to do this is to work your way down through the hash with && symbols - if any step is nil (or false), the line will return nil (or false) rather than exploding. eg
puts hash['recipes'] && hash['recipes'][text].is_a?(Hash) && hash['recipes'][text].keys
Note i'm testing that hash['recipes'][text] is a hash (rather than just a string for example) before calling .keys on it.

How to deduplicate the code getting parameters and checking nil in Ruby

token = params[:token]
email = params[:email]
phone_number = params[:phone_number]
iso_code = params[:iso_code]
if token.nil? or email.nil? or phone_number.nil? or iso_code.nil?
raise InvalidParameterException
end
token.strip!
email.strip!
phone_number.strip!
iso_code.strip!
#use the variables
There are many this code in my rails project.
How do you generalization this pattern in Ruby on Rails?
Is it possible with reflection and meta programming?
unless [:token, :email, :phone_number, :iso_code].-(params.keys).empty?
raise InvalidParameterException
end
params.each{|_, v| v.strip!}
Then, just use it like params[:token] each time. Maybe you can use a shorter variable name for params like p.
I don't think that metaprogramming or patterns are necessary in this case, just common sense:
[:token, :email, :phone_number, :iso_code].each do |k|
raise InvalidParameterException if params[k].nil?
params[k] = params[k].strip
end
I've never understood the popularity of this anti-pattern:
par_1 = params[:par_1]
...
par_n = params[:par_n]
Why not use the params[:par_x] instead? It's usually more convenient to work with params variables grouped in a hash than have them stored into bunch of local variables.
You can define the method below :
def verify_presence_define_var_and_strip(params, symbol_list)
symbol_list.each do |s|
raise InvalidParameterException if params[s].nil?
define_method s, params[s].strip
end
end
With this method, your code could be replace by :
verify_presence_define_var_and_strip(params, [:token, :email, :phone_number, :iso_code])
Notice that it will define method and not just set a local variable but you should have the same result if you do not already have a method with this name in your class.
You may prefer to use the instance_variable_set method but you will have to preceed the variable name by an #.
[UPDATE]
If you really want to define local variable and not method / instance variable, I do not know other solution than using eval :
eval "#{s} = #{params[:s].strip}"
But as you will find if you search about eval, it is considered as bad practice, moreover in this case where you will evaluate values from URL / POST parameters !
Create a helper method that access the params hash and iterates through the elements and checks for nil and throws the exception itself or returns a value to the calling method that could throw the exception.
You can iterate any hash like so,
hash.each do |key,value|
#example nil check
if value.nil?
#do what you want
end
end
If you want to raise on nil in your hash of parameters you could do
raise InvalidParameterException if params.values.include? nil
If you only want to raise on some specific parameters you would have first to pick the values associated to those keys:
required_keys = [:key1, :key2, :key3]
raise invalidParameterException if required_keys.map{|k| params[k]}.include? nil
EDIT: Cannot answer because of lack of points but one of the answer does not work I believe:
[:some_key] - {some_key: nil}.keys # => []
If the parameter hash contains one key initialized with value nil (as a result of a failed parse or invalid user input), Array subtraction does not work.

Setting many key/value pairs

I'm working on a rake task which imports from a JSON feed into an ActiveRecord called Person.
Person has quite a few attributes and rather than write lines of code for setting each attribute I'm trying different methods.
The closest I've got is shown below. This works nicely as far as outputing to screen but when I check the values have actually been set on the ActiveRecord itself it's always nil.
So it looks like I can't use .to_sym to solve my problem?
Any suggestions?
I should also mention that I'm just starting out with Ruby, have been doing quite a bit of Objective-c and now need to embrace the Interwebs :)
http = Net::HTTP.new(url.host, url.port)
http.read_timeout = 30
json = http.get(url.to_s).body
parsed = JSON.parse(json)
if parsed.has_key? 'code'
updatePerson = Person.find_or_initialize_by_code(parsed['code'])
puts updatePerson.code
parsed.each do |key, value|
puts "#{key} is #{value}"
symkey = key.to_sym
updatePerson[:symkey] = value.to_s
updatePerson.save
puts "#{key}....." # shows the current key
puts updatePerson[:symkey] # shows the correct value
puts updatePerson.first_name # a sample key, it's returning nil
end
You're probably looking for update_attributes():
if parsed.has_key?('code')
code = parsed.delete('code')
person = Person.find_or_initialize_by_code(code)
if person.update_attributes(parsed)
puts "#{person.first_name} successfully saved"
else
puts "Failed to save #{person.first_name}"
end
end
Your code can not assign any attribute, because you are always assigning to the single attribute named "symkey":
symkey = key.to_sym
updatePerson[:symkey] = value.to_s # assigns to attribute "symkey", not to the attribute with the name stored in variable symkey
If you want to make key into a symbol (which is probably not even necessary) and then use that as an index to access the attribute in updatePerson, you can write:
updatePerson[key.to_sym] = value.to_s
updatePerson.save
But this - more or less - is the same as
updatePerson.updateAttribute(key.to_sym, value.to_s) # update and save
except that no validation is triggered, so use with care.
And performancewise it might not be such a good idea to save the person after each assignment, so maybe you want to defer the .save() call until after you have assigned all attributes.
Nevertheless, updateAttributes(...) is something you might want to be looking into - if you do, do not forget to inform yourself on attr_protected or attr_accessible, as they protect attributes from "bulk assignment"
You can use write_attribute:
parsed.each do |key, value|
updatePerson.write_attribute(key, value)
end
updatePerson.save

Resources