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.
Related
I am running into an issue, where I need to check if a class exists. However, I am passing the class to a variable and trying to check it from there.
My issue is I need to pass the actual constant for defined?() to work, but I'm passing a variable, so instead of seeing a constant, it sees a method or variable.
obj is a rails model instance, for example, a specific User, or a specific Car.
def present(obj, presenter_class=nil, view_context=nil)
klass = presenter_class || "#{obj.class}Presenter".constantize
if defined?(klass) == 'constant' && klass.class == Class
klass.new(obj, view_context)
else
warn("#{self}: #{klass} is not a defined class, no presenter used")
obj
end
end
Pry Output:
[1] pry(ApplicationPresenter)> defined?(klass)
=> "local-variable"
I tried the below, but I get a method back...
[18] pry(ApplicationPresenter)> defined?("UserPresenter".constantize)
=> "method"
How can I fix this issue?
Well, apparently Object#defined? does not the thing that you hoped it would do.
tests whether or not expression refers to anything recognizable (literal object, local variable that has been initialized, method name visible from the current scope, etc.). The return value is nil if the expression cannot be resolved. Otherwise, the return value provides information about the expression.
Your goal looks like you are rebuilding what the draper gem is doing with .decorate... Don't forget that most of the gems are open source and you can use that for trying things on your own. See for example the decorator_class method from them
decorator_name = "#{prefix}Decorator"
decorator_name_constant = decorator_name.safe_constantize
return decorator_name_constant unless decorator_name_constant.nil?
They use the method safe_constantize and this apparently returns nil when the constant is not available.
2.6.5 :007 > class UserPresenter; end;
=> nil
2.6.5 :008 > 'UserPresenter'.safe_constantize
=> UserPresenter
2.6.5 :009 > 'ForgottenPresenter'.safe_constantize
=> nil
To me that looks exactly like what you need, and it also safer than using constantize
def present(obj, presenter_class=nil, view_context=nil)
klass = presenter_class || "#{obj.class}Presenter".safe_constantize
if klass != nil
klass.new(obj, view_context)
else
warn("#{self}: #{klass} is not a defined class, no presenter used")
obj
end
end
I am getting a request from mobile app. They are sending a variable isbookmarked that can be either 1 or 0. I am checking in if statement.
if isbookmarked
do something
else
do something
end
The else part is never executed because 0 is not recognised as false
How can I achieve this?
In Ruby everything is truthy except for nil and false. Thus both 0 and 1 are truthy - you will never reach the else part with this set up.
So in your case you want to check exactly for 0 or 1:
if isbookmarked == 1
do something
elsif isbookmarked == 0
do something
end
You can use this gem called wannabe_bool, you will get a to_b method which can convert almost everything to boolean, you can check the gem documentation for all the options available.
if isbookmarked.to_b
do something
else
do something
end
I have tried few of the things on console that might help you
2.0.0-p451 :002 > "1".to_b
=> true
2.0.0-p451 :003 > "0".to_b
=> false
2.0.0-p451 :004 > 1.to_b
=> true
2.0.0-p451 :005 > 0.to_b
=> false
https://github.com/prodis/wannabe_bool
Hope that helps!
A helper method like below may come in handy.
def truthy?(val)
val.present? && !val.to_s.strip.in?(['false', '0'])
end
So, in addition to #AndreyDaineko, you also can use case
case isbookmarked
when 1
do something
when 0
do something
else
something go wrong
end
I would argue that you should use the same logic that Rails uses to identify booleans. Rails implements type casting to booleans like this:
FALSE_VALUES = [false, 0, "0", "f", "F", "false", "FALSE", "off", "OFF"].to_set
def cast_value(value)
if value == ""
nil
else
!FALSE_VALUES.include?(value)
end
end
You can use this implementation like this (Rails 5 version):
ActiveModel::Type::Boolean.new.cast(isbookmarked)
Or the Rails 4.2 versions would look like this:
ActiveRecord::Type::Boolean.new.type_cast_from_user(isbookmarked)
You can also use zero? to check whether the value is zero or not. But there is no special method to check 1 only way isbookmarked == 1
if isbookmarked.zero?
do something
else
do something
end
I really don't know what I am not seeing here, because it looks to me that "if false" is acting like "if true". To make it clear, I actually took screenshots of my RubyMine 6.0.3 screens. This one is probably simple, but it surely looks crazy to me...
The code is in DevicesController#update. It has a breakpoint that occurs within an "if false" statement that shouldn't be executing. See in this shot that I am on line 48 within the if:
The variable dump at this time follows, that shows that params[:device][:chg_pwd], the if condition, is false.
So, why am I within this if statement when its condition is false?
"false" is true in ruby. you want == "true"
In Ruby, only nil and false are false. For more, you can read this gist
if params[:device][:chg_pwd] == "true"
Depending on your situation, the other options are
Set to nil, or false. Then your existing code would work.
Set to "" and check with blank? as a previous version of RSB's answer
used to say, this is Rails only though, and does involve a small
semantic difference (blank vs false)
It returns "false", which is a string, so it returns true.
if params['is_admin'] == 'true'
# YOUR CODE goes HERE
end
Use this instead of "false" as "false" is a string and not a boolean value in your code
if params[:devise][:chg_pwd].eql?("false")
# code
else
# code
end
This would explain it better
2.0.0p247 :012 > if "true"
2.0.0p247 :013?> p "hello"
2.0.0p247 :014?> end
"hello"
=> "hello"
2.0.0p247 :015 > if "false"
2.0.0p247 :016?> p "hi"
2.0.0p247 :017?> end
"hi"
=> "hi"
I'm on Rails 3.0.x, Ruby 1.9.2 and needs a way to test for params that may or may not exists, e.g.,
params[:user] #exists
params[:user][:login] #may not exist
What's the proper Ruby syntax for the 2nd check so it doesn't barf?
Try following:
params.has_key? :user #=> true because exists
params[:user].has_key? :login #=> true if exist otherwise false
#WarHog has it right, pretty much. It's very unusual for an item in params to sometimes return a string but other times return a Hash, but regardless you can handle that easily enough:
if params.has_key?(:user) && params[:user].respond_to?(:has_key?)
do_something_with params[:user][:login]
end
Instead of respond_to? :has_key? you could also do respond_to? :[] or just is_a? Hash. Mostly a matter of preference.
You would just get nil in the second case.. that shouldn't be a problem, no?
e.g. params[:user][:login] just returns nil, which evaluates to false if the :user entry exists in the first Hash.
However if the nesting would be one or more levels deeper, and the missing hash entry was somewhere in the middle, you would have problems. e.g.:
params[:user][:missing_key][:something]
in that case Ruby would try to evaluate nil[:something] and raise an exception
you could do something like this:
begin
x = params[:user][:missing_key][:something]
rescue
x = nil
end
... which you could further abstract...
This is really racking my brain, but maybe I'm trying to hard.
I'm passing a param via a URL (example.com?debug=true)
So I basically want to say:
if params[:debug] == true
do xyz
else
do abc
end
But for whatever reason that if statement just isn't doing like it seems like it should.
Is there a better way to do that if/else statement based on a param being true or false?
The debug param will either have a value of true, no value, or a value of false (as far as the URL goes).
params come in as strings, so you need to compare against "true", not true.
You could use ActiveRecord's method of checking truthful values if you don't want to reinvent the wheel (this is what is used when passing params inside an ActiveRecord object
Rails 3-4.1
if ActiveRecord::ConnectionAdapters::Column.value_to_boolean(params[:debug])
do xyz
else
do abc
Rails 4.2.0
ActiveRecord::Type::Boolean.new.type_cast_from_database(params[:debug])
Rails 5
ActiveModel::Type::Boolean.new.cast(params[:debug])
Might be worth wrapping in a helper but never the less it's quite flexible:
rails c
Loading development environment (Rails 3.2.6)
1.9.3p194 :001 > ActiveRecord::ConnectionAdapters::Column.value_to_boolean '1'
=> true
1.9.3p194 :002 > ActiveRecord::ConnectionAdapters::Column.value_to_boolean '0'
=> false
1.9.3p194 :003 > ActiveRecord::ConnectionAdapters::Column.value_to_boolean 1
=> true
1.9.3p194 :004 > ActiveRecord::ConnectionAdapters::Column.value_to_boolean true
=> true
1.9.3p194 :005 > ActiveRecord::ConnectionAdapters::Column.value_to_boolean 'true'
=> true
1.9.3p194 :006 > ActiveRecord::ConnectionAdapters::Column.value_to_boolean 'on'
=> true
1.9.3p194 :007 > ActiveRecord::ConnectionAdapters::Column.value_to_boolean 'off'
Custom extension
Some people frown on extending core classes but this does fit with the DRY principle.
# config/initializer/boolean.rb
class Boolean
def self.parse(value)
ActiveRecord::ConnectionAdapters::Column.value_to_boolean(value)
end
end
Then used like
if Boolean.parse(params[:debug])
then xyz
Since Rails/ActiveRecord 4.2.0 it is
if ActiveRecord::Type::Boolean.new.type_cast_from_user params[:debug]
do xyz
else
do abc
end
In Rails 5 it is:
if ActiveModel::Type::Boolean.new.cast params[:debug]
do xyz
else
do abc
end
But for whatever reason that if statement just isn't doing like it seems like it should.
I can almost guarantee that it is doing exactly what it should. When things don't make sense, one of our assumptions is wrong.
Is the value actually a boolean or is it string (or something else?). If the value is a string then of course the comparison to the boolean value true will fail. Try comparing to 'true' and see if that works.
how about this?
params[:debug].to_s.downcase == 'true'