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'
Related
This question already has answers here:
How to dynamically create a local variable?
(4 answers)
Closed 5 years ago.
In Ruby, how can I interpolate a string to make a variable name?
I want to be able to set a variable like so:
"post_#{id}" = true
This returns a syntax error, funnily enough:
syntax error, unexpected '=', expecting keyword_end
I believe you can do something like:
send("post_#{id}=", true)
That would require, of course, that you have appropriate setter/getter. Which, since you're doing this dynamically, you probably don't.
So, perhaps you could do:
instance_variable_set("#post_#{id}",true)
To retrieve the variable:
instance_variable_get("#post_#{id}")
BTW, if you get tired of typing instance_variable_set("#post_#{id}",true), just for fun you could do something like:
class Foo
def dynamic_accessor(name)
class_eval do
define_method "#{name}" do
instance_variable_get("##{name}")
end
define_method "#{name}=" do |val|
instance_variable_set("##{name}",val)
end
end
end
end
In which case you could:
2.3.1 :017 > id = 2
=> 2
2.3.1 :018 > f = Foo.new
=> #<Foo:0x00000005436f20>
2.3.1 :019 > f.dynamic_accessor("post_#{id}")
=> :post_2=
2.3.1 :020 > f.send("post_#{id}=", true)
=> true
2.3.1 :021 > f.send("post_#{id}")
=> true
2.3.1 :022 > f.send("post_#{id}=", "bar")
=> "bar"
2.3.1 :023 > f.send("post_#{id}")
=> "bar"
This concerns the getting and setting of local variables. Suppose
id = 1
s = "post_#{id}"
#=> "post_1"
Since Ruby v1.8 it has not been possible to create local variables dynamically. Therefore, if a local variable post_1 does not exist, the only way you can create it is by using an assignment statement:
post_1 = false
If the local variable post_1 exists, you can retrieve its value dynamically with
b = binding
b.local_variable_get(s)
#=> false
(or b.local_variable_get(s.to_sym)) and set its value dynamically with
b.local_variable_set(s, true)
#=> true
post_1
#=> true
(or b.local_variable_set(s.to_sym, true)).
See Binding#local_variable_get and Binding#local_variable_set.
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
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 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"
My "Project" Table have invoice as integer attribute, Here I put nil object to this attribute in DB. During evaluation nil.empty? occurs.
Code written at HAML extentions
- #project.each do |proj|
=proj.invoice if !proj.invoice.blank? || !proj.invoice.empty? || !proj.invoice.nil?
- #project_invoice=proj.invoice
=#project_invoice=0 if proj.invoice.blank? || proj.invoice.empty? || proj.invoice.nil
I receive this error while running code.
NoMethodError: You have a nil object when you didn't expect it!
You might have expected an instance of Array.
The error occurred while evaluating nil.empty?
There's a few standard tests provided by Ruby and rails that can help, but you usually don't need to use all of them at once:
# Rails provided Object#blank? method
nil.blank? # => true
false.blank? # => true
''.blank? # => true
[ ].blank? # => true
# Ruby provided Object#nil? method
nil.nil? # => true
false.nil? # => false
''.nil? # => false
[ ].nil # => false
# Ruby class-specific #empty? method
nil.empty? # => error
false.empty? # => error
''.empty? # => true
[ ].empty? # => true
In your case the test you're probably looking for is actually a different one altogether. The opposite of blank? is present? and it comes in very handy for situations like this. You can even collapse down both of your inverted logical tests into a simple ternary query:
- #project_invoice = proj.present? ? proj.invoice : 0
More verbosely it looks like this:
- if (proj.present?)
#project_invoice = proj.invoice
- else
#project_invoice = 0
The present method verifies that the variable represents a non-nil, non-blank value of some sort.
The second condition has a misspelled variable name. It should be proj, not projt.
That would cause your issue.
if the invoice column is nill, then !proj.invoice.blank? evaluates to false, and the next test is done, !projt.invoice.empty?
since invoice is nil, you have nil.empty? which is an error, as empty? can not run on nil.
ruby-1.9.2-p0 > !nil.blank? || !nil.empty?
NoMethodError: You have a nil object when you didn't expect it!
You might have expected an instance of Array.
The error occurred while evaluating nil.empty?
I think you are doing an overkill, since an integer should not be an array. I think you should just shorten it to only test blank?, as that catches an empty array too.
Is this is the code you are using. If this is the same code, I see a spelling mistake in the
second line.
Can you try with
=proj.invoice if !proj.invoice.blank? || !proj.invoice.empty? || !proj.invoice.nil?