Implement a sort as a class method in Ruby - ruby-on-rails

ActiveRecord gives me a back a set of Users. I want to sort those users by a complex function that uses data not persisted in the User object.
Is there a way to use a scope when the data isn't persisted?
Is there a way to write a sort function as a class method, so I can make a call like:
sorted_users = User.first(20).sorted_my_way

i think it is not possible to do it this way.
it is possible to define class methods and scopes that can be called like User.first(20).sorted_my_way but those can only append stuff to the query you create. if you want to sort within ruby, i think that you need to wrap the whole stuff like:
class User
self.sorted_my_way(limit)
first(20).sort_by {...}
end
end
User.sorted_my_way(20)
another thing that you could do would be to use a block style method:
class User
self.sorted_my_way
yield.sort_by {...}
end
end
User.sorted_my_way { first(20) }

Related

How to return something from a Concern and update a record?

I want to move some class methods for some of my models that are the same to a concern.
One method takes an input and returns something which then should be used to update a record like this:
def create_sort_title
self.sort_title = self.title.gsub(/^the |^a |^an /i, '').gsub(/'|"|!|\?|-/, '').gsub(/(?<!\w) /,'')
end
While it's clear that I need to refactor it to take an input:
def create_sort_title(title)
self.sort_title = title.gsub...
...
I don't understand how I can RETURN a value to update a record - i. e. how to replace the self.sort_title above with something that then is used to update the sort_title of the corresponding record?
The method is called by a before_safe hook:
before_save :create_sort_title
(and I understand once I take an argument, I need to use a lambda like this:
before_save -> { create_sort_title(title) }
You don't really need to pass any arguments if you're using a concern that is included on the model. When you do include ConcernName you're adding class and/or instance methods on the model class/instance itself. So your create_sort_title method that is called from before_save callback will have access to all instance methods, including title and will work as-is just fine

How to check if a variable has a map available in rails? In other words, if a variable is mappable?

I am trying to deal with a legacy method which accepts a variable and returns the variable.amount.to_s. But now with some changes, the variable can also be an active record relation.
I basically want to be able to do something like this:
def method(variable)
if variable has map?
variable.map { |v| v.amount.to_f }.reduce(:+)
variable.to_s
else
variable.amount.to_s
end
end
but I am unable to figure out what that if condition should be ?
You can test for the method directly with respond_to?.
if variable.respond_to?(:map)
Or you can check that it is Enumerable which provides a large suite of methods used for iteration, including map.
if variable.is_a?(Enumerable)
The advantage of Enumerable is it tells you more about the object, and you can be more sure that its map is the map you expect and not just some method that happens to be named map. The disadvantage is it will miss anything which is not Enumerable but does implement an applicable map; I can't think of a case where that should happen.

How to determine a const in some model class?

There is the following model for 'delivery_types' table:
class DeliveryType < ActiveRecord::Base
end
I want to determine a special delivery type, for example, "DELIVERY_BY_TIME", and I want that this const returns DeliveryType.first (I'll put info about this type in my table later). Is it possible? How can I do it? Thanks.
I don't think you can do this, as this is no "real const". What you could do though, is creating a class method, called "by_time", which returns your "by_time" object. I would also not rely on the fact that this is your "first" object. Rather I would use a "find_or_create_by_name("BY_TIME"), which always makes sure you deliver the right object. Combined, something like
def self.by_time
##by_time||= find_or_create_by_name!(name: 'BY_TIME')
end
def by_time?
self == DeliveryType.by_time
end
If you read "Rails anti-patterns", they discourage you from making separate classes for "status" fields. They recommend to just use a string for that in your parent object, with some validators that limit the list of values though...

Ruby on Rails Class method scoped objects references

I was wondering If I could modify objects using a class method.
For example, users = User.scoped # This will select all the objects
And, suppose, I want to assign a variable for each of the object there is. Let's say, I want them to share a single value. So, when I try to access, for example, users.first.my_variable it would produce the value, I want.
My naive implementation:
def self.set_my_variable(variable_value)
scoped.tap do |obj|
obj.my_variable = variable_value
end
end
So, ideally, when I wan't this variable to be set, I should call the class method like this: users.set_my_variable("hello, stackoverflow")
But, when I try accessing the variable through arbitrary object of the set, like this:
users.first.my_variable
I get nil. Comparing .object_id's in both: obj.object_id and users.first.object_id shows that they are different. Why so ? I thought that they share the same reference (pointing to the same objects)
Any way of fixing it (preferrably without passing a collection to this class method) ?
you need to save object to database:
obj.my_variable = variable_value
obj.save

Something like $ or ## variable, but unique for each user session. Rails

I have array of objects. I can't store it in DB for performance reason. I tried store array in Global ($var) and Class (##var) variables (in controller), but it was the same array for all users. It should be unique for each user session and in each session it should be able to be modified quickly.
I understand that the session[] - is not the best solution. What is the best way?
I'm doing something like this $lines_rules << Processing::rule_creator(...) in every time, when run action in controller.
$lines_rules - it is my array of objects.
Why DB is not right for store $lines_rules? In $lines_rules I store objects with lambda function. When user press button I need call every lambda function with user input and keep result. Then I load new objects into $lines_rules. Thus every request change $lines_rules. I think work with memory is the better way for perfomance.
UPDATE
I use $global_hash [ session[:session_id] ] and this technique for resource saving:
def dead_sessions_killer
ActiveRecord::SessionStore::Session.where(["updated_at < ?", 30.minutes.ago]).each do |session|
$global_hash.delete_if {|key, value| key == session.session_id }
session.delete
end
end
Use a global, but a global hash, keyed by the user's session id.
Store whatever you want in there, although with proper caching, hard to say if this is a great idea.
You could declare the array as a class variable (only 1 # sign), and provide an accessor method.
That is:
class Foo
#some_array
def some_array
#some_array
end
end
From other classes, this lets you call foo_instance.some_array, which keeps the array specific to the user, but allows public access from any class.
You could store the user session in memory with memcache. That would be convenient and fast.
http://awesomerails.wordpress.com/2011/08/23/rails-3-memcached-session-store/

Resources