Rails scope/class method selecting virtual attribute - ruby-on-rails

I'm currently using the has_scope gem in conjunction with scopes/class methods on models to filter result sets returned to my UI.
I have a model Task which I'd like to be able to filter by status -- a virtual attribute on the model.
The Task model has a few attributes which you might need to know about
uuid: Generated by SecureRandom
running: A boolean
success: A boolean
started_at: DateTime
The status is calculated as such:
def status
if running?
'Running'
elsif started_at.nil?
'Queued'
elsif success?
'Finished'
else
'Failed'
end
end
Ignoring the fact that this is probably not an ideal way of doing this, I have currently implemented the status filtering method like so:
def self.by_status(status)
records = all.select {|s| s.status == status}
where(uuid: records.map(&:uuid))
end
I cannot return just the results from select as it's of type Array as opposed to an ActiveRecord::Relation, hence my where hackery. For context the reason I cannot/do not want to return an array is the result-set is passed to kaminari for pagination.
Please note: The method I currently use meets my requirements, but I don't like the way it's done. I feel like there should be a better way.
Can anyone suggest a better by_status method for returning an ActiveRecord::Relation?
tl;dr:
Need a class method to return an ActiveRecord::Relation filtering on a virtual attribute.
Thanks in advance.

Here is how I would do it
def self.by_status(status)
case status
when 'Running' then where(running: true)
when 'Finished' then where(success: true)
when 'Queued' then where(started_at: nil)
else scoped #change this to all in Rails 4 since Model.all returns an AR Relation
end
end

Related

Sort a returned object by its boolean parameters [Ruby]

i think i used the right terminology for what i need, i currently have a database call in my home_controller that is returning a call to my database with all the entries in that table specified, Freelancer.
There is an attribute on these records that has either a true or false value, which is "featured".
I need a way to call a sort method, or some other way, on that object with the true being first and then the false being afterwards, i tried using this code
def index
#freelancers = Freelancer.all
p 'below im outputting featured freelancer i hope'
#freelancers.sort_by { |row| [row.featured ? 0 : 1, row.id]}
p #freelancers
end
But unfortunately this did not work, can anyone advise me on a way to get this to work? Id rather have the sorted object returned as is, rather then assigning it to a new one. Just for future features of adding pagy and a filter by cost.
Use order method
def index
#freelancers = Freelancer.order(featured: :desc)
end

Rails: Applying function to every record in table?

I have a table in Rails and I would like to find all records of a table where a certain function returns true.
What is the best way to do this? I could of course iterate over all the records in the table and use conditional statements to test whether the function, given the individual record, returns true and add it to a list.
Is there any easier way of doing this something along the lines of Model.find(:all, :conditions => {...}) maybe?
Thanks
Class MyModel < ActiveRecord
def self.targetted
find_each.select(&:predicate_method?)
end
def predicate_method?
#something that returns either true or false
end
end
this is a bit more Rails idiomatic :
find_each will fetch your record by batches of 1000. it is better than all for your memory
&:predicate_method : transforming a symbol into a Proc (with the # operator) will actually make your code call the method on each of the passed objects
def record_that_returns_true_for_xfunction
Model.all.select {|record| xfunction(record.some_column) == true}
end
This is seems like what you are looking for. This method will return an array of all the records where xfunction(record.some_column) == true.

Rail3 'Return False Unless XYZ' Query Not Working

In my rails3.1 application, I'm trying to apply the following logic in one of my order model.
def digital?
line_items.map { |line_item| return false unless line_item.variant_id = '102586070' }
end
I've created a separate variant called prepaid_voucher which has id = 102586070. Despite this, the result is false...
Order has many line_items
LineItem belongs to order and variant
Variant has many line_items
Is this the best way to perform such a task and how can I fix?
First of all I think you want a double == here line_item.variant_id = '102586070', then I rather go for something like that (If I understand what you want)
def digital?
line_items.select{|line_item| line_item.variant_id == '102586070'}.any?
end
But it's hard to understand what you really want, what is the expected behavior if the id is not found?

Rails scope with HABTM relationship count

I have an Event class with a HABTM relationship with a User class. I'm trying to create a Event scope that includes only Events that have 2 Users associated with it.
I currently have a Event#status method that returns the following:
def status
self.users.length == 2 ? "matched" : "not matched"
end
So now basically I'm trying to find how to write a scope that includes all "matched" events. I tried scope :matched, self.users.length == 2, which didn't work at all, but is there a similar way that I'm missing?
EDIT: This class method does this correctly, but it'd still be nice if I could encapsulate it in a scope.
def self.pending
Event.all.map { |e| e if e.status == "matched" }
end
You've got a few problems here. Right now, your status method is returning literal strings, which is a bit surprising -- it would be more common to have this return a Boolean value. Also, the name status is not descriptive -- perhaps exactly_two_users? would be better. In addition, if you use users.count instead of users.length, then the DB will do the count more efficiently.
Your scope could simply be where(:users.count => 2), I believe.

Getting the name of Ruby method for a literal hash query

In a rails application, I have a number of attributes for a model called Record. I want to design a method that when called on an attribute, returns the name of the attribute (which is essentially a method on the Record object). This name is then passed to an Hash, which returns a number (for the sake of this example, say the number is a percentage which is then multiplied by the original attribute value to get a new value).
For example, say my Record has four attributes: teachers, students, principals, and parents. The method would then look like the following:
def name
**something here**
end
and the corresponding new_value method and PRECENTAGE hash would look like this:
def new_value
self * PERCENTAGE[self.name]
end
PERCENTAGE = {
"teachers" => 0.40,
"students" => 0.53,
"principals" => 0.21,
"parents" => 0.87
}
Then, to execute this whole thing, I would do Record.students.new_value, which would return new number of students according to the percentage obtained in the hash.
I know that to get the name of a method that is currently executing, you can do something like this: (found on http://ryat.la/7RDk)
def this_method
__method__
end
but that won't work for me, because I need the name of the previously executed method.
If you have any suggestions as to an alternative approach to accomplishing my goal, I'd be happy to try something else.
Ryan, I'm struggling to understand your question, but I think this is what you want, for record.teachers_percent, for example:
["teachers", "students", "principals", "parents"].each do |attrib|
Record.class_eval <<-RUBY
def #{attrib}_percent
#{attrib} * PERCENTAGE[#{attrib.inspect}]
end
RUBY
end
Although this is probably a cleaner solution, giving record.percent(:teachers) or record.percent("teachers"):
class Record
def percent(attrib)
self.send(attrib) * PERCENTAGE[attrib.to_s]
end
end

Resources