How do attribute query methods work? - ruby-on-rails

I.e., is
Post.title?
equivalent to
Post.title.present?

No.
Object#present? is the same thing as calling !obj.blank?.
The "attribute?" method might end up calling the same code, but it might not, and it depends on the column type that you're dealing with.
The easiest way to see these not return the same value is to access a numeric column. Say you had foo.score as a decimal column in your db, and you set it to zero. You'd see the following behavior.
foo.score = 0
foo.score? # false
foo.score.present? # true
The code for the "?" method is in ActiveRecord::AttributeMethods.
def query_attribute(attr_name)
unless value = read_attribute(attr_name)
false
else
column = self.class.columns_hash[attr_name]
if column.nil?
if Numeric === value || value !~ /[^0-9]/
!value.to_i.zero?
else
return false if ActiveRecord::ConnectionAdapters::Column::FALSE_VALUES.include?(value)
!value.blank?
end
elsif column.number?
!value.zero?
else
!value.blank?
end
end
end

Related

How to update a specific field in Mongodb knowing it's name?

I have the following code
def update_field(db_entity, field_name)
db_entity_value = db_entity.attributes[field_name]
if db_entity_value == false
db_entity.update(field_name: true) # db_entity.update(person_name: true) works!
end
end
it takes two vars: db_entity and field_name(it's a string value like "age" or "weight"). I want to update the value of field_name.
I can get its value by using db_entity.attributes[field_name] and then I want to set the value to true if it was false, but I don't know how to update it because field_name it's a variable which holds a field name that I want to update. Please, help.
def update_field(db_entity, field_name)
db_entity_value = db_entity.attributes[field_name]
if db_entity_value == false
db_entity.update(field_name => true)
end
end
In Ruby when you construct hashes with the hashrocket (=>) syntax the keys can be variables.
You can also use update_attribute(name, value).

Do something if value is present

I frequently find myself writing Ruby code where I check for the presence of a value and subsequently do something with that value if it is present. E.g.
if some_object.some_attribute.present?
call_something(some_object.some_attribute)
end
I think it would be cool, if it could be written as
some_object.some_attribute.presence { |val| call_something(val) }
=> the return value of call_something
Anyone know if there's such a feature in Ruby or though activesupport?
I opened a pull request for this feature.
You can use a combination of presence and try:
If try is called without arguments it yields the receiver to a given block unless it is nil:
'foo'.presence.try(&:upcase)
#=> "FOO"
' '.presence.try(&:upcase)
#=> nil
nil.presence.try(&:upcase)
#=> nil
You could try
do_thing(object.attribute) if object.attribute
This is usually fine, unless the attribute is a boolean. In which case it will not call if the value is false.
If your attribute can be false, use .nil? instead.
do_thing(object.attribute) unless object.attribute.nil?
Though there is no such functionality out of the box, one could do:
some_object.some_attribute.tap do |attr|
attr.present? && call_smth(attr)
end
On the other hand, Rails provides so many monkeypatches, that one could append one to this circus:
class Object
def presense_with_rails
raise 'Block required' unless block_given?
yield self if self.present? # requires rails
end
def presense_without_rails
raise 'Block required' unless block_given?
skip = case self
when NilClass, FalseClass then true
when String, Array then empty?
else false
end
yield self unless skip
end
end

Ruby on Rails - unless multiple conditions

I'm trying to substitute an expression unless the expression is one of two values.
def substitute_string (string)
string.gsub('abc', 'xyz') unless string == ('dabc' || 'eabc')
end
substitute_string('jjjjjabc')
=> 'jjjjjxyz'
substitute_string('dabc')
=> 'dabc'
substitute_string('eabc')
=> 'exyz'
I expected substitute_string('eabc') to return ('eabc') since I stated that in the unless block, which I passed two values.
I don't understand why this doesn't work, and what I can do to make 'eabc' return 'eabc'.
('dabc' || 'eabc') is a boolean expression that evaluates to true and returns 'dabc'.
Use two or's:
unless string == 'dabc' || string == 'eabc'
Or use =~ (regex pattern match)
unless string =~ /(dabc|eabc)/
Since you indicated you're using Rails, you can also use in? like this:
unless string.in? ['dabc', 'eabc']
It is because (1) 'dabc' || 'eabc' is equivalent to 'dabc', and nowhere in your code does 'eabc' appear in a meaningful way, and because (2) it only returns nil when the condition is met according to the way you used unless.
def substitute_string(string)
case string
when 'dabc', 'eabc' then string
else string.gsub('abc', 'xyz')
end
end
Apart from the fun of obscure technicalities about what is returned when and in what situations, I don't see a lot of merit in not being more explicit with the return. The very fact that this issue was brought and subsequently debated on SO is exactly why writing code (working code to be sure) in this obscure fashion will lead to confusion for developers interpreting this code, and leads to buggy software.
The only benefit I see to this is that it's on one line.
def substitute_string(string)
string.gsub('abc', 'xyz') unless ['dabc', 'eabc'].include?(string)
end
I personally would prefer the following as it makes it clear what your intentions are:
def substitute_string(string)
return string if ['dabc', 'eabc'].include?(string)
string.gsub('abc', 'xyz')
end
'dabc' || 'eabc' will always equal true since it just means condition or condition where condition is a string. Since a string is not nil or false it evaluates to true. You could check whether the string is in an array values instead:
def substitute_string(string)
string.gsub('abc', 'xyz') unless ['dabc', 'eabc'].include?(string)
end

Check string is a valid number or not in ruby

I want to check weather variable contains a valid number or not.
I can validate correctly for null and blank but can not validate text as a "Integer"...
I tried:
if(params[:paramA].blank? || (params[:paramA].is_a?(Integer)) )
I have also tried is_numeric, is_numeric(string), is_number? and other ways...
but did not get success...
I saw such patch:
class String
def is_number?
true if Float(self) rescue false
end
end
if (params[:paramA].blank? || !params[:paramA].is_number?)
Or without the patch:
if (params[:paramA].blank? || (false if Float(params[:paramA]) rescue true))
It supports 12, -12, 12.12, 1e-3 and so on.
If your parameter is for an ActiveRecord model, then you should probably use validates_numericality_of. Otherwise...
You only want integers, right? How about:
if (params[:paramA].blank? || params[:paramA] !~ /^[+-]?\d+$/)
That is, check whether the parameter consists of an optional + or -, followed by 1 or more digits, and nothing else.
If the thing you want to do is this:
I want to check weather variable contains a valid number or not.
You can get it with regex. See it here
s = 'abc123'
if s =~ /[-.0-9]+/ # Calling String's =~ method.
puts "The String #{s} has a number in it."
else
puts "The String #{s} does not have a number in it."
end
In rails you can use the numeric? method on a String or Integer or Float which does exactly what you need.
123.numeric?
# => true
123.45.numeric?
# => true
"123".numeric?
# => true
"123.45".numeric?
# => true
"a1213".numeric?
# => false
UPDATE
My bad, I had a dirty environment, the above works if mongoid version 3 and above is loaded.

Can I do this in Ruby?

Currently I have the following 2 lines of code
errors.add_to_base I18n.t :error_message if value != 1
return false if !errors.blank?
Is it possible to condense this into 1 line of code? I need to do this in multiple places with different error message and condition. Also, "return false" is to stop the flow of an ActiveRecord lifecycle.
Hmm. If you know errors.blank? will be true unless the first condition fires then:
(errors.add_to_base I18n.t :error_message; return) if value != 1
Update: Aha, you are willing to define a method. How about a Proc object? It's better than a method here in that if the Proc block returns then the invocation will return from the surrounding method.
test = Proc.new do |cond, msg|
errors.add_to_base I18n.t msg if cond
return unless errors.blank?
end
# ...
test.call value != 1, :error_message
Note that you don't need to return false as a plain return will return nil and that will be good enough unless some sadist is doing something like f().class == NilClass. :-)
You can take advantage of how the boolean logic operators work and do something like this:
value != 1 && errors.add_to_base I18n.t :error_message && return false
Not very clear, I wouldn't recommend using it. Also if errors.add_to_base returns something that's "falseish" the return false wouldn't happen.
Remember: "Always code as if the person who will maintain your code is a violent psychopath who knows where you live”

Resources