what I want to query is somethinkg like
Model.where(condition: params[:condition]) if params[:condition] exists.
otherwise its okay to return all.
I came up with one liner like Model.where(condition: params[:condition] || 0..Float::INFINITY)
but it didn't work.
Model.where(condition: 0..Float::INFINITY) works as I expected, so I thought above also would work.
Do you guys have any good idea to query by oneliner? I know ternary operator should work.
params[:condition] || (0..Float::INFINITY) will only return (0..Float::INFINITY) in the case that params[:condition] is nil or false:
{ condition: "" }[:condition] || (0..Float::INFINITY)
# => ""
{ condition: false }[:condition] || (0..Float::INFINITY)
# => 0..Infinity
{ condition: nil }[:condition] || (0..Float::INFINITY)
# => 0..Infinity
You could use Object#presence to check if the value is not false, is empty, or a whitespace string:
{ condition: "" }[:condition].presence || (0..Float::INFINITY)
=> 0..Infinity
otherwise its okay to return all
As I understand you need different scopes depend on condition
You can use chaining in that case
For example
models = Model.all
models = models.where(condition: params[:condition]) if params[:condition]
So if params[:condition] is truthy: some where scope will be used
If not: all records will be used
It's not one liner. But quite convenient
Related
I am trying to perform a sort_by on a hash, but whenever I have a nil value I get:
comparison of DateTime with nil failed
My goal is to perform a nil check (.present?) on x[:last_posted_at] inside the sort_by method. Is that possible? Example code:
posts = [
{ "name"=>"Alice", "last_posted_at"=> some_datetime },
{ "name"=>"Bob", "last_posted_at"=> nil},
{ "name"=>"Clark", "last_posted_at"=> some_datetime - 1}
]
# expected result
posts.sort_by.{ |x| x[:last_posted_at] } #compare only if value is not nil
#=> [{"name"=>"Alice", "last_posted_at"=> some_datetime},
# {"name"=>"Clark", "last_posted_at"=> some_datetime - 1},
# {"name"=>"Bob", "last_posted_at"=> nil}]
I looked into the sort_by documentation and some of the posts here in stackoverflow, but I cannot find my answer. Any help or links are welcome! Thanks in advance!
I like Schwern's approach. But if there are more records without a date then another option might be to separate record without dates from the records with dates and only sort thoses with a date like this:
posts
.partition { |v| v['last_posted_at'] } # separate by date presence
.tap { |v| v.first.sort_by! { |v| v['last_posted_at']} } # only sort entries with a date
.flatten # combine into one list again
Use presence to return the value or nil, and || to return a default value if it is blank.
# Something sufficiently old to be older than any other time.
nil_time = Time.at(0)
posts.sort_by.{ |x|
x[:last_posted_at].presence || nil_time
}
Note: DateTime is deprecated.
I've tried reading some tutorials on refactoring and I am struggling with conditionals. I don't want to use a ternary operator but maybe this should be extracted in a method? Or is there a smart way to use map?
detail.stated = if value[:stated].blank?
nil
elsif value[:stated] == "Incomplete"
nil
elsif value[:is_ratio] == "true"
value[:stated] == "true"
else
apply_currency_increment_for_save(value[:stated])
end
If you move this logic into a method, it can be made a lot cleaner thanks to early return (and keyword arguments):
def stated?(stated:, is_ratio: nil, **)
return if stated.blank? || stated == "Incomplete"
return stated == "true" if is_ratio == "true"
apply_currency_increment_for_save(stated)
end
Then...
detail.stated = stated?(value)
stated = value[:stated]
detail.stated = case
when stated.blank? || stated == "Incomplete"
nil
when value[:is_ratio] == "true"
value[:stated] == "true"
else
apply_currency_increment_for_save stated
end
What's happening: when case is used without an expression, it becomes the civilized equivalent of an if ... elsif ... else ... fi.
You can use its result, too, just like with if...end.
Move the code into apply_currency_increment_for_save
and do:
def apply_currency_increment_for_save(value)
return if value.nil? || value == "Incomplete"
return "true" if value == "true"
# rest of the code. Or move into another function if its too complex
end
The logic is encapsulated and it takes 2 lines only
I like #Jordan's suggestion. However, it seems the call is incomplete -- the 'is_ratio' parameter is also selected from value but not supplied.
Just for the sake of argument I'll suggest that you could go one step further and provide a class that is very narrowly focused on evaluating a "stated" value. This might seem extreme but it fits with the notion of single responsibility (the responsibility is evaluating "value" for stated -- while the 'detail' object might be focused on something else and merely makes use of the evaluation).
It'd look something like this:
class StatedEvaluator
attr_reader :value, :is_ratio
def initialize(value = {})
#value = ActiveSupport::StringInquirer.new(value.fetch(:stated, ''))
#is_ratio = ActiveSupport::StringInquirer.new(value.fetch(:is_ratio, ''))
end
def stated
return nil if value.blank? || value.Incomplete?
return value.true? if is_ratio.true?
apply_currency_increment_for_save(value)
end
end
detail.stated = StatedEvaluator.new(value).stated
Note that this makes use of Rails' StringInquirer class.
I have the following in my events controller:
def index
#event = Event.search(params[:search]).events_by_category(params[:cat]).order(...).paginate(...)
end
And in my events model, I have the following class method:
def self.events_by_category(cat)
if cat == 0
all
elsif cat && cat != 0
where('category = ?', cat)
else
scoped
end
end
And in my view I have a standard search box for the search and dropdown for the category selection. The category options_for_select has an array that includes ["All Categories", 0] in it.
My question is: Why does this return no results instead of all results when All Categories is selected in the dropdown. And, when I change the array to ["All Categories", "ALL"] and the if statement to if cat == "ALL" it returns Undefined method 'order'?
I think it has something to do with stringing the search and events_by_category together in the controller, but searches and categories work just fine in conjunction when it's not All Categories being selected...
Any help would be GREATLY appreciated!
To answer your second question first: the problem is that your cat == "ALL" condition returns Event.all, which is a Ruby Array, not an ActiveRecord::Relation. order is an activerecord method not an array method, that's why you're getting the error Undefined method 'order'.
If you want to return all results for the category ALL, then change all to scoped (which will return a scope with no conditions on it). That will be chainable, so that you can call it with order and paginate.
As to your first question, params[:cat] is a string so you should be checking whether cat == "0" not cat == 0. I think that should solve the problem.
Your conditional, by the way, is a bit convoluted: you're testing if cat is 0, then checking that it is not 0 in the else statement, but you already know that it is not 0. I'd suggest simplifying your method code to this:
def self.events_by_category(cat)
(cat && cat != "0") ? where('category = ?', cat) : scoped
end
This says: if the category is present and not "0" (i.e. not the category "all results"), then return results for that category, if not return all results.
def self.events_by_category(cat)
if cat == "0"
all
elsif cat && cat != "0"
where('category = ?', cat)
else
scoped
end
end
The above will work.
I'm looking through my object attributes for culprits that are not :
^[1-3]{3}$
What is the method used to scan integers for regexp?
Some examples:
124.to_s.match(/^[1-3]{3}$/)
=> nil
123.to_s.match(/^[1-3]{3}$/)
=>#<MatchData "123">
Since nil is considered as false, you have your boolean.
Ex:
"no yo" if 124.to_s.match(/^[1-3]{3}$/)
=> nil
"yo!" if 123.to_s.match(/^[1-3]{3}$/)
=> "yo!"
You may use also one of the following:
def is_pure_integer?(i)
i.to_i.to_s == i.to_s
end
or
'132' =~ /^\d+$/ ? true : false
I can't quite figure out what I'm doing wrong here..
if #calc.docket_num =~ /DC-000044-10/ || #calc.docket_num =~ /DC-67-09/
#calc.lda = true
else
#calc.lda = false
end
But it seems that #calc.docket_num can be any string whatsoever and it always returns as true.
Am I not doing this right?
This is a one-liner:
#calc.lda = !!(#calc.docket_num =~ /DC-000044-10|DC-67-09/)
The !! forces the response to true/false, then you can assign your boolean variable directly.
Alternatively you could use the triple equals (===) operator for the Regexp class which is used for determining equality when using case syntax.
#calc.lda = /DC-000044-10|DC-67-09/ === #calc.docket_num
#calc.lda
=> true
BEWARE
/Regexp/ === String is totally different than String === /Regexp/!!!! The method is not commutative. Each class implements === differently. For the question above, the regular expression has to be to the left of ===.
For the Regexp implementation, you can see more documentation on this (as of Ruby 2.2.1) here.
I think the issue is somewhere else in your implementation. Use this code to check it:
k = 'random information'
if k =~ /DC-000044-10/ || k =~ /DC-67-09/
puts 'success'
else
puts 'failure'
end
=> failure