Rails 2-cases scope - ruby-on-rails-3

I have scope
scope :for_list, lambda { |brand_ids|
where('brands.id IN (?)', brand_ids).includes(:models).where("models.popular = '1'").order('models.name')
}
But some times there are no models.popular = 1
And in this case I want to select all from models ignoring popular parameter
How to write that scope?

Since it's simply a lambda function, you can use an if/else in there and it'll get evaluated at the time it's called. Therefore, you could write the scope like this:
scope :for_list, lambda { |brand_ids|
if self.popular > 1
where('brands.id IN (?)', brand_ids).includes(:models).where("models.popular = '1'").order('models.name')
else
where('brands.id IN (?)', brand_ids).includes(:models).order('models.name')
end
}
That should work. However, I'd caution against using this. That logic doesn't belong in a scope. Instead, you should question you your views and controllers are set up and rework those.

Related

Rails: How to use instance method in Active Record Query

I am having a filter query which should return all the records where either
attribute (column) "status" is not "done", or
instance method "completeness_status" does not return "done"
The query is something like that:
Studies.where("studies.status != ? OR studies.completeness_status != ?", "done", "done")
but I am getting error that column completeness_status does not exist.
Unfortunately, the column status is not continuously updated, so I cannot use it only. Also, the instance method "completeness_status" is based on records from other tables.
I try to add a scope to my model and use this instance method as scope but also I was not successful.
Also, I tried to used it as class method but then I do not know how to call it from where clause.
def self.completeness_status(study)
# code
end
or
def self.completeness_status_done?(study)
# code return true or false
end
Any Idea how to solve that.
Thanks.
You cannot use instance methods inside your query. But if you like to check the condition of completeness for only one row, then you can use it as instance method:
first_study = Study.first
first_study.completeness_status_done?
Also, if you provide more information about what is going on inside your completeness_status_done? then maybe I can give you some ideas to use scopes.
https://guides.rubyonrails.org/active_record_querying.html

How to use lamda to get not equals value on a scope in ruby on rails?

I have a scope thats not currently working.
scope :not_voided, lambda { where('workflow_state != ?', "voided") }
I want to get all orders that don't have a workflow_state of "voided"
I'm really struggling with it and any help would be appreciated.
This code actually works as expected.

ActiveRecord - Compare two values in same row

I have a table of call data and I want to query all unanswered calls, which means that the call start time is equal to the call end time. I currently use the following plain SQL which works as expected:
select * from calls where calls.start = calls.end
I was wondering if there is a more "rails" way to do this using the ActiveRecord Query Interface. Ideally I'd like to set up a scope in my Call model that returns me all unanswered calls. Something like:
scope :unanswered, -> { where(start: :end) }
The above doesn't work because Rails treats :end as a string instead of the end column in the DB.
I'm using PostgreSQL as my DB engine.
The SQL query
select * from calls where calls.start = calls.end
could be done in a rails way using a scope as follows:
scope :unanswered, -> { where('start = end') }
I think you can do the following:
scope :unanswered, -> (end) { where(start: end) }

How can I find percent complete in ActiveRecord?

I can't seem to find an elegant way of doing this.
But let's say my model Projects has many Tasks.
Each task has a boolean field for complete.
So if I have 10 tasks and 4 are "complete" and 6 are not, then I am only 40% complete.
Is there a slick way of doing this in a scope so that the SQL is lean?
I already have two scopes like:
scope :complete, lambda {
where("tasks.complete = true")
}
scope :not_complete, lambda {
where("tasks.complete = false")
}
Thanks for any tips.
I would think that since you're looking to get a final value out of this a model method would be the best approach. (scopes should return a Relation in order to support chaining) You could use these scopes to return the percent complete, something along the lines of:
def percent_complete
not_complete.size.to_f / complete.size.to_f
end
Or if you require big_decimal and big_decimail/util in your model you could use to_d to get decimal division. Then in your view all you have to do is #project.percent_complete

Rails scope that does nothing for NOT IN values

I have a Rails 3 scope that excludes an array of ids.
What is the best way to write the scope so that it does nothing when the array is empty and is still chainable? I currently have this, which works, but seems a little hokey:
scope :excluding_ids,
lambda {|ids| ids.empty? ? relation : where('id not in (?)', ids) }
If I do not have the "ids.empty? ? relation :" bit, when ids is empty the SQL generated is
... ID not in (NULL) ...
which will always return nothing. So something like:
Model.excluding_ids([]).where('id > 0')
returns no results.
If the ids array is empty then don't return anything.
scope :excluding_ids, lambda { |ids|
where(['id NOT IN (?)', ids]) if ids.any?
}
The query will run without any additional constraints on the query if there are no ids.
In Rails 4 you can use:
scope :excluding_ids, ->(ids) { where.not(id: ids) }
Here's a slight variation on Douglas' answer, using ruby 1.9 stabby lambda syntax and without the brackets in the where method.
scope :excluding_ids, ->(ids) {where("id NOT IN (?)", ids) if ids.any?}
How about the following? (It still checks for an empty array though, so if that's what you're trying to avoid it's not much of an improvement :)
scope :excluding_ids,
lambda {|ids| (ids.empty? && relation) || where('id not in (?)', ids) }