I saw this...
How to convert activerecord results into a array of hashes
and wanted to create a method that would allow me to turn any scoped or non-scoped record set into an array of hashes. I added this to my model:
def self.to_hash
to_a.map(&:serializable_hash)
end
However, I get this error.
NameError: undefined local variable or method `to_a' for #<Class:0x007fb0da2f2708>
Any idea?
You probably need to call all on that too. Just the to_a would work fine on a scope or existing result set (e.g. User.active.to_hash) but not directly on the model (e.g. User.to_hash). Using all.to_a will work for both scenarios.
def self.to_hash
all.to_a.map(&:serializable_hash)
end
Note that the all.to_a is a little duplicative since all already returns an array, but in Rails 4 it will be necessary.
You're performing the action on a class, not an instance of the class. You can either take away the self. then call this on an instance, or to call it on a collection you need to pass the collection into the class method:
def self.to_hash(collection)
collection.to_a.map(&:serializable_hash)
end
Related
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.
I've got a query that does some math and returns a calculated custom select field with the result set. I cannot figure out how to access that in the activerecord object that is returned. I've added an attr_accessor for it also.
attr_accessor :percentage_used
select('gateways.*, (num_transactions_today/ SUM(num_transactions_today)) AS percentage_used ').joins(:gateway_groups).where('map_gateway_groups.gateway_group_id = ?', gateway_group_id)
in the result set, I would expect to have access to :percentage_used, but it is not in there. Any ideas on what i'm doing wrong? i've never needed to do this before.
Thanks
You can access it as
object["percentage_used"]
You neither need nor want attr_accessor for that. attr_accessor creates an instance variable, an accessor method for getting the value of that instance variable, and a mutator method for changing its value. When you say this:
select('gateways.*, (num_transactions_today/ SUM(num_transactions_today)) AS percentage_used ...
ActiveRecord will automatically add a percentage_used method to the returned objects. But the percentage_used method for accessing that value will be added by method_missing. Since you've said attr_accessor :percentage_used, method_missing will never be called and you can't get at the percentage_used value from the query in the usual way.
If you drop the attr_accessor :percentage_used, then you'll be able to call percentage_used on objects returned by that select and you'll find the values you're looking for. However, AR won't be able to convert the value to a native Ruby number though so you'll have to to_f the returned string yourself.
I have some rails services which (depending on the service) accept a specific type of object, an Array of that object, or an ActiveRecord::Relation of that object.
So:
FooService accepts Foo objects, BarService accepts Bar objects, etc.
But..all the service objects want to massage what is passed in into an array of their given objects.
within the scope of the called service method I could do this pretty easily.
I was trying to DRY things up and make a method to do this for all services, because each of them had the same chunk of code. Unfortunately, I run into issues with Ruby.
For example:
def change_obj(element)
element = [element]
end
blah = "hello"
change_obj(blah)
puts blah.class.to_s #I want it to be an array with the string in it now.
I understand why it doesn't work. But, I don't have a clear idea of what the correct way to do this is.
Ideally I want something like:
class BarService < Service
def initialize(foo)
#foo = foo
end
def do_something(bars)
massage_to_array(bars) #method inherited from Service. if bars is an ActiveRecordRelation, convert it to array..if bars is a singular object, flip it to an array with that object as the sole element.
process_array_of_bars(bars)
end
end
bars = massage_to_array(bars)
process_array_of_bars(bars)
as long as you are modifying passed object - ruby will keep the reference and update contents of that object and not create new object. For example if you pass an array as argument and then add element to an array inside the method - ruby will add element to the object that was passed in, but if you re-assign value to the object, then ruby will remove the reference to passed object and create new object in the local scope and add reference to it to the variable name.
That being said, you can still achieve similar result by creating class that will acts as a proxy. Remember ruby will maintain reference to original object as long as you dont re-assign the variable name to new variable. For example
class ArgProxy
attr_accessor :arg_object
def initialize(arg=nil)
self.arg_object = arg
end
end
def some_method(arg_proxy)
arg_proxy.arg_object = [arg_proxy.arg_object]
end
arg_proxy = ArgProxy.new("qwerty")
some_method(arg_proxy)
arg_proxy.arg_object #=> ["qwerty"]
Question: Is it possible to build a class method scope that can query objects based on values inside an array in a table? If yes, how can I do this?
In my example, I have a “wells” table that has an array field called “well_tags”. I want to build a query that returns all objects that have a specified value (such as “ceramic”) in the wells_tags array. The basic query would be something like this:
#well = Well.all
#query = #well.where(“well_tags contains ceramic”)
And then the class method scope would look something like this, with the “well_tag_search” param passed in from the controller:
class Well < ActiveRecord::Base
def self.well_tag_filter(well_tag_search)
if well_tag_search.present?
where(“well_tags contains ceramic")
else
Well.all
end
end
I found another post that asks a similar question (see link below), but I cannot get the answer to work for me...the result is always 'nil' when I know there should be at least 1 object. I am a beginner using sqlite (for now) as my database and rails 4.0.
Active Record Query where value in array field
Thanks!
UPDATE: some progress
I figured out how to create an array of all the objects I want using the ‘select’ method. But I still need to return the results as an Active Record object so I create a class method scope.
#well = Well.select
{ |well| if well.well_tags.present?
then well.well_tags.include? ‘ceramic' end }
#well.class #=> array
Not sure where Show is coming from.
Can you try doing Well.all instead of Show.all?
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