I'm using Rails 5. I see many posts about getting a boolean from a string, but I would like to go the reverse path. I was wondering if there is a more elegant way than this ...
my_boolean_value ? "true" : "false"
You can use to_s to transform true or false to a string. But you only want that if your value is different than nil. The .nil? method will return true or false (if the variable is nil or not). The exclamation mark negates the assertion. In that case, if it's NOT nil, to_s method will be called.
my_boolean_value.to_s if !my_boolean_value.nil?
You can use my_boolean_value.to_s. Basically it will convert booleans to string.
You can also do "#{my_boolean_value}"
Note: If my_boolean_value can be .nil? or anything other then true/false then your solution in the question is the best and simplest way to do it. You can use following way as well if you don't want to use ternary operator,
(!!my_boolean_value).to_s
But I still think from readability and maintainability point of view, you should use the solution given in the question. Reason would be, you are doing double negation can be confusing if you don't put comments around.
More elegant way? No. More practical way? Maybe.
# in app/helpers/application_helper.rb
module ApplicationHelper
def boolean_label_for(value)
BooleanLabel.to_s(value)
end
end
# in lib/boolean_label.rb
class BooleanLabel
def self.to_s(value)
new(value).to_s
end
def initialize(value)
#value = value
end
def to_s
if #value
"true"
elsif #value.nil?
"i am nil — false"
elsif #value
"false"
end
end
end
It's not overly sexy and you could argue it's unnecessarily complicated, but if you find yourself implementing this check a lot, you should DRY it up.
Try
ActiveRecord::Type::Boolean.new.type_cast_from_user(my_boolean_value).to_s
Related
I need to set the id parameter to a value if it is wasn't submitted with the form.
Is it ok to do something like this in Rails or does this violate any standards or cause possible issues?
if params[:cart][:cart_addresses_attributes]["0"][:id].blank?
params[:cart][:cart_addresses_attributes]["0"][:id] = 1234 #default id
end
My implementation works with this logic, but I am not sure if this is the proper way to handle the issue.
There's a chance [:record_type] is nil which will lead to an undefined method error when you attempt to call [:id] on nil. Additionally, I'd find it a bit weird to directly mutate params, even though you technically can do that. I'd consider using Strong Parameter processing methods like so (added a full action, which isn't in your sample, to give more context on how this would be used):
def create
#record_type = RecordType.new(record_type_params)
if record_type.save
redirect_to #record_type
else
render :new
end
end
def record_type_params
params.require(:record_type).permit(:id).reverse_merge(id: 1234)
end
The reverse_merge call is a way to merge the user-supplied parameters into your defaults. This accomplishes what you're after in what I would consider a more conventional way and doesn't mutate params.
def cart_params
params.require(:cart).permit(:cart_addresses_attributes => [:id]).tap do |p|
p[:cart_addresses_attributes]["0"][:id] ||= 1234
end
end
if params[:record_type][:id].nil? # or replace ".nil?" with "== nil"
params[:record_type][:id] = 1234
end
personally, this is the way I prefer to do it. Some ways are more efficient than others, but if that works for you I'd roll with it.
I'm reading Rails Devise gem documentation and it says:
If the page could potentially not have a current_user set then:
if current_user.try(:admin?) # do something end
I have tried it without question mark
current_user.try(:admin)
and it works the same way returning true or false.
Do I miss something? Is there any difference and how can I see it?
Ruby is somewhat unusual in that it lets you include a wide range of characters in the names of methods including ? and !.
They have no special significance to the interpreter but the language convention is that:
methods ending with ? are interrogative - they should ALWAYS return true or false.
methods ending with ! either mutate the object the are called on or may raise a exception.
So why does it matter at all? In this particular case it does not matter since your user class has an accessor for the #admin instance variable created by ActiveRecord - just like any other column.
If it did not however current_user.try(:admin) would always return nil. Remember that instance variables are always private in Ruby until you provide an accessor*.
# Just a plain old Ruby class - not an ActiveRecord model
class User
def initialize
#admin = true
end
def admin?
#admin
end
end
User.new.try(:admin) # is always nil...
This is because User does not respond to :admin and .try prevents a NoMethodError and just returns nil instead.
ActiveRecord and accessors:
In a plain old ruby class you would add accessors to make the instance variable #admin available:
class User
def initialize
#admin = true
end
attr_accessor :admin
end
Which does this:
class User
def initialize
#admin = true
end
# getter
def admin
#admin
end
# setter
def admin=(val)
#admin = val
end
end
ActiveRecord reads the schema from your database and uses metaprograming to auto-magically add accessors to your model classes. They are a bit more complex than the example above but its the same basic principle. Thats why your User model responds to #admin.
By default, rails ActiveRecord object attributes that are boolean can either be called with or without a question mark (?).
By convention, it is easier to read if you add the ?, and that also shows that it is boolean at first glance.
So, reading this gives the impression that you are asking a question in English.
Therefore, my guess is that admin is a boolean field on the user.
Also, Tom above is very correct.
There is probably no functional difference, in this case.
I'm guessing admin is a boolean field in the users database table. So, user.admin will return either true or false -- no surprises here!
For each column in the table, Rails will also automatically generate an associated method prepended with an ?. For example, if you have a column foo, then there will be a method foo? - which will return true or false depending on the value of foo.
For example, if current_user.name == "Tom" then current_user.name? == true. And if current_user.name == nil, then current_user.name? == false.
It's very rarely necessary to use the ? methods in your code, since all objects are either "truthy" or "falsey" in ruby anyway. But it can sometimes be useful to show intent, and makes the code easier to read, as it's clear that the value is only being used in a boolean manner.
I have this class-level method in an ActiveRecord model class.
def self.is_animal_color_correct?(animal, color)
if AnimalColor.find_by_animal_and_color(animal.downcase, color.downcase)
true
else
false
end
end
I'm just wondering what the best way to format the method is. This seems verbose, but very clear.
In this particular example, I think this is what you want instead:
AnimalColor.exists?(:animal => animal.downcase, :color => color.downcase)
In general, you should not care as long as you are checking against truthy, that anything not null or false.
def self.is_animal_color_correct?(animal, color)
AnimalColor.find_by_animal_and_color(animal.downcase, color.downcase)
end
It is idiomatic in Ruby to use nil and false as non-truthy values and real values (when available) for truthy ones. With your if/else you are actively discarding information that might be useful somewhere else, and doing more work in the process.
If you really really really want your method to return only true or false, you could:
def self.is_animal_color_correct?(animal, color)
!!AnimalColor.find_by_animal_and_color(animal.downcase, color.downcase)
end
But again, this is not idiomatic Ruby, and I do not recommend it.
I am not experienced in Ruby, so my code feels "ugly" and not idiomatic:
def logged_in?
!user.nil?
end
I'd rather have something like
def logged_in?
user.not_nil?
end
But cannot find such a method that opposites nil?
You seem overly concerned with booleans.
def logged_in?
user
end
If the user is nil, then logged_in? will return a "falsey" value. Otherwise, it will return an object. In Ruby we don't need to return true or false, since we have "truthy" and "falsey" values like in JavaScript.
Update
If you're using Rails, you can make this read more nicely by using the present? method:
def logged_in?
user.present?
end
when you're using ActiveSupport, there's user.present? http://api.rubyonrails.org/classes/Object.html#method-i-present%3F, to check just for non-nil, why not use
def logged_in?
user # or !!user if you really want boolean's
end
Beware other answers presenting present? as an answer to your question.
present? is the opposite of blank? in rails.
present? checks if there is a meaningful value. These things can fail a present? check:
"".present? # false
" ".present? # false
[].present? # false
false.present? # false
YourActiveRecordModel.where("false = true").present? # false
Whereas a !nil? check gives:
!"".nil? # true
!" ".nil? # true
![].nil? # true
!false.nil? # true
!YourActiveRecordModel.where("false = true").nil? # true
nil? checks if an object is actually nil. Anything else: an empty string, 0, false, whatever, is not nil.
present? is very useful, but definitely not the opposite of nil?. Confusing the two can lead to unexpected errors.
For your use case present? will work, but it's always wise to be aware of the difference.
Maybe this could be an approach:
class Object
def not_nil?
!nil?
end
end
May I offer the Ruby-esque ! method on the result from the nil? method.
def logged_in?
user.nil?.!
end
So esoteric that RubyMine IDE will flag it as an error. ;-)
You can just use the following:
if object
p "object exists"
else
p "object does not exist"
end
This does not only work for nil but also false etc, so you should test to see if it works out in your usecase.
I arrived at this question looking for an object method, so that I could use the Symbol#to_proc shorthand instead of a block; I find arr.find(&:not_nil?) somewhat more readable than arr.find { |e| !e.nil? }.
The method I found is Object#itself. In my usage, I wanted to find the value in a hash for the key name, where in some cases that key was accidentally capitalized as Name. That one-liner is as follows:
# Extract values for several possible keys
# and find the first non-nil one
["Name", "name"].map { |k| my_hash[k] }.find(&:itself)
As noted in other answers, this will fail spectacularly in cases where you are testing a boolean.
"output" is a serialized OpenStruct.
def title
try(:output).try(:data).try(:title)
end
What would be better? :)
Or simply this:
def title
output.data.title rescue nil
end
Referring to this blog you might find it better to use the &. operator like below for ruby version > 2.3.0;
output&.data&.title
def try_chain
yield
rescue NoMethodError
nil
end
def title
try_chain { output.data.title }
end
Thoughtbot just talked about this on their blog, using what they call it's a Shallow Nil:
def swallow_nil
yield
rescue NoMethodError
nil
end
So, in their example, they could do something like:
campaign = swallow_nil { supporter.politician.campaign }
Or, in your case,
def title
swallow_nil { output.data.title }
end
However, be aware that any of your bugs will also be swallowed and would be hard to find, specially since it traps every NoMethodErrors, which would be caused from other parts of your code (although if you use testing, this helps a lot).
Another approach would be to use andand, where your code would be then
def title
output.andand.data.andand.title
end
Not as clean as the swallow_nil one, but probably best to not just ignore everything.