Actually I am new to rails I was trying to build authentication from scratch but didn't have any idea. So I was reading some code on internet and I am struck at a function.What does !! means over here. Is it first making it false then true? What it is and why we are using it?
def logged_in?
!!current_user
end
! means "not", so !! means "not-not". ! is often called "bang" (because 'exclamation mark' is too long, i assume) and so !! is often called "double bang". See also "hashbang" or "shebang" which mean #!.
It has the effect of converting all "truthy"* things into the boolean true and all "falsy" things into the boolean false.
Note that in Ruby, unlike some languages, the only things that are "falsy" are false and nil. 0, "", [], {}, and any other object that isn't false or nil, such as a User object, are "truthy".
*"truthy" means it will pass an "if" test.
We use double bang to get value as Boolean (true/false). Here is demonstration:
2.1.2 :001 > my_var = "string"
=> "string"
2.1.2 :002 > !my_var
=> false
2.1.2 :003 > !!my_var
=> true
2.1.2 :005 > null_var = nil
=> nil
2.1.2 :006 > !!null_var
=> false
So, as you can see that, if we want to get corresponding boolean value for an object then we use double bang (!!).
In your case, I assume current_user can have user object OR nil value. Instead of getting user object or nil, it's using !! to convert it into corresponding boolean.
Hope it helps. Happy Learning!
EDIT:
I would like to add that in Ruby, it's convention that method name ending with ? will return boolean value. So, your mentioned code us using !! in logged_in? to return boolean instead of User or NULL class objects.
You are trying to do something like this
def logged_in?
current_user
you are asking here if it is a current user
def logged_in?
!current_user
while you are asking here is the logged in user is not current_user.
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
I have a database object in active record. If I call object.find(1).present? it returns false, but it exists. Calling !object.find(1).nil? returns true.
Why is this? I thought !nil == present?.
nil? and present? are not opposites.
Many things are both not present? and not nil?, such as an empty string or empty array.
"".present? # => false
"".nil? # => false
[].present? # => false
[].nil? # => false
To better answer your question lets look at the implementation:
def present?
!blank?
end
We don't see nil? mentioned here, just blank?, so lets check out blank? as well:
def blank?
respond_to?(:empty?) ? !!empty? : !self
end
So essentially, if the object responds_to empty? it will call out to that for the result. Objects which have an empty? method include Array, Hash, String, and Set.
Further Reading
The Blank/Present Source in ActiceSupport
A concise explanation of nil v. empty v. blank in Ruby on Rails
I'm submitting a parameter show_all with the value true. This value isn't associated with a model.
My controller is assigning this parameter to an instance variable:
#show_all = params[:show_all]
However, #show_all.is_a? String, and if #show_all == true always fails.
What values does Rails parse as booleans? How can I explicitly specify that my parameter is a boolean, and not a string?
UPDATE: Rails 5:
ActiveRecord::Type::Boolean.new.deserialize('0')
UPDATE: Rails 4.2 has public API for this:
ActiveRecord::Type::Boolean.new.type_cast_from_user("0") # false
PREVIOUS ANSWER:
ActiveRecord maintains a list of representations for true/false in https://github.com/rails/rails/blob/master/activerecord/lib/active_record/connection_adapters/column.rb
2.0.0-p247 :005 > ActiveRecord::ConnectionAdapters::Column.value_to_boolean("ON")
2.0.0-p247 :006 > ActiveRecord::ConnectionAdapters::Column.value_to_boolean("F")
This is not part of Rails' public API, so I wrapped it into a helper method:
class ApplicationController < ActionController::Base
private
def parse_boolean(value)
ActiveRecord::ConnectionAdapters::Column.value_to_boolean(value)
end
end
and added a basic test:
class ApplicationControllerTest < ActionController::TestCase
test "parses boolean params" do
refute ApplicationController.new.send(:parse_boolean, "OFF")
assert ApplicationController.new.send(:parse_boolean, "T")
end
end
I wanted to comment on zetetic answer but as I can't do that yet I'll post this as an answer.
If you use
#show_all = params[:show_all] == "1"
then you can drop ? true : false because params[:show_all] == "1" statement itself will evaluate to true or false and thus ternary operator is not needed.
This question is rather old, but since I came across this issue a couple of times, and didn't like any of the solutions proposed, I hacked something myself which allows to use multiple strings for true such as 'yes', 'on', 't' and the opposite for false.
Monkey patch the class String, and add a method to convert them to boolean, and put this file in /config/initializers as suggested here: Monkey Patching in Rails 3
class String
def to_bool
return true if ['true', '1', 'yes', 'on', 't'].include? self
return false if ['false', '0', 'no', 'off', 'f'].include? self
return nil
end
end
Notice that if the value is none of the valid ones either for true or false, then it returns nil. It's not the same to search for ?paid=false (return all records not paid) than ?paid= (I don't specify if it has to be paid or not -- so discard this).
Then, following this example, the logic in your controller would look like this:
Something.where(:paid => params[:paid].to_bool) unless params[:paid].try(:to_bool).nil?
It's pretty neat, and helps to keep controllers/models clean.
#show_all = params[:show_all] == "1" ? true : false
This should work nicely if you're passing the value in from a checkbox -- a missing key in a hash generates nil, which evaluates to false in a conditional.
EDIT
As pointed out here, the ternary operator is not necessary, so this can just be:
#show_all = params[:show_all] == "1"
You could change your equality statement to:
#show_all == "true"
If you want it to be a boolean you could create a method on the string class to convert a string to a boolean.
I think the simplest solution is to test "boolean" parameters against their String representation.
#show_all = params[:show_all]
if #show_all.to_s == "true"
# do stuff
end
Regardless of whether Rails delivers the parameter as the String "true" or "false" or an actual TrueClass or FalseClass, this test will always work.
You could just do
#show_all = params[:show_all].downcase == 'true'
It's worth noting that if you're passing down a value to an ActiveModel in Rails > 5.2, the simpler solution is to use attribute,
class Model
include ActiveModel::Attributes
attribute :show_all, :boolean
end
Model.new(show_all: '0').show_all # => false
As can be seen here.
Before 5.2 I use:
class Model
include ActiveModel::Attributes
attribute_reader :show_all
def show_all=(value)
#show_all = ActiveModel::Type::Boolean.new.cast(value)
end
end
Model.new(show_all: '0').show_all # => false
Another approach is to pass only the key without a value. Although using ActiveRecord::Type::Boolean.new.type_cast_from_user(value) is pretty neat, there might be a situation when assigning a value to the param key is redundant.
Consider the following:
On my products index view by default I want to show only scoped collection of products (e.g. those that are in the stock). That is if I want to return all the products, I may send myapp.com/products?show_all=true and typecast the show_all parameter for a boolean value.
However the opposite option - myapp.com/products?show_all=false just makes no sense since it will return the same product collection as myapp.com/products would have returned.
An alternative:
if I want to return the whole unscoped collection, then I send myapp.com/products?all and in my controller define
private
def show_all?
params.key?(:all)
end
If the key is present in params, then regardless of its value, I will know that I need to return all products, no need to typecast value.
You can add the following to your model:
def show_all= value
#show_all = ActiveRecord::ConnectionAdapters::Column.value_to_boolean(value)
end
You could convert all your boolean params to real booleans like this:
%w(show_all, show_featured).each do |bool_param|
params[bool_param.to_sym] = params[bool_param.to_sym] == "true"
end
In this solution, nil parameters would become false.
While not explicitly what the question is about I feel this is appropriately related; If you're trying to pass true boolean variables in a rails test then you're going to want the following syntax.
post :update, params: { id: user.id }, body: { attribute: true }.to_json, as: :json
I arrived at this thread looking for exactly this syntax, so I hope it helps someone looking for this as well. Credit to Lukom
def role?(role)
return !!self.roles.find_by_name(role.to_s.camelize)
end
Can you help me understand what's happening in the code above? I'm new to Rails/Ruby.
Thanks
It's negation (!) operator repeated twice.
Note that only ruby objects evaluating to false (in boolean expression) are nil and false itself.
Therefore,
some_role will be true, !some_role is false and !!some_role is true again.
nil is false, !nil is true and !!nil is false.
So, this is a "clever" way to check whether role returned from find_by_name is nil or not. (And therefore whether role with such name exists or not)
I guess, I don't have to tell you that doing this is bad for readability. You can always check if result is nil by normal means, like result.nil? or result == nil.
This is more readable. No need for the 'self' or 'return'. 'present?' is the opposite of 'nil?' so no negation is required.
def role?(role)
roles.find_by_name(role.to_s.camelize).present?
end