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.
Related
If I have a jsonb column activerecord returns the attribute as a hash but somehow retains a reference to that object so it is able to detect changes. That is, code behaves like the following
pub = Publication.find("554a1791-e690-4a45-8207-db6b66fa3480")
md = pub.metadata #jsonb column
pub.metadata_changed? #false
md['foo'] = 'bar'
pub.metadata_changed? #true
I'd like to replace the hash class with an instance of a custom class but retain the modification in place behavior. What do I need to do to achieve this? Do I overload some kind of method to check if the object is dirty?
Hey I wasn't quite sure what to call this but here's the deal.
I'm trying to only assign things to my database value if
There isn't a value in the database already, and
The value I'm assigning isn't blank.
The rudimentary version of this code is:
venue.address = venue_json['address'] if venue.address.blank? && !venue_json['address'].blank?
where venue is my ActiveRecord result.
This is what I have now (a little better). With the init_value in the Venue.rb class.
Venue.init_value(venue.address, venue_json['address'])
def self.init_value(record, value)
if record.blank? && !value.blank?
record = value
end
end
I'd like to get to this point, but really have no idea how.
venue.address.init_value(venue_json['address'])
especially since I'd like it it work with any attribute of the ActiveRecord class not just the address value.
Separating it into a method sounds like a good idea, but in this case it makes more sense to use an instance method rather than a class method.
def init_attribute(attribute, value)
self.update(attribute => value) if self.send(attribute).blank? && value.present?
end
venue.init_attribute(:address, venue_json['address'])
Some quick comments on the snippet above:
Using direct assignment won't persist the database value. You could go with something else like update or update_column. Or you can use assignment and then call #save on the object.
Whenever you need something not to be blank, you can use the more readable Object#present? which is part of ActiveSupport.
You'll need to call the method with the same name as the attribute on the database object. For this you'll want to use Object#send from Ruby.
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
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