I'm trying to dynamically append a relational object to it's associated object using the send method. For example:
car = Car.first
tire = Tire.first
car.send('tires<<', tire)
But I always get method undefined. I realize in this simple example it's not necessary to use send, but in my case it is. Any help appreciated, thanks.
There is no tires<< method, there is a << method defined on object returned by tires. Try:
car.send('tires') << tire
Related
I was wondering if I could update a record (entire row) given a replacement activerecord object.
Something like
Car.find_by(number: 1) = replacement_information_for_car_1
where replacement_information_for_car_1 is a Car activerecord object that I would like to use to replace the old record currently on the table.
You could do something like:
attributes = replacement_information_for_car_1.attributes
attributes.delete('id') # and anything else you don't want/can't be copied
Car.find_by(number: 1).update(attributes)
Not the cutest thing in the world, but it should do the trick.
The thing about ActiveRecord objects is that they have a unique identifier that you don't want to override. You'll have to assign the attributes without the id, that is most likely to be nil in your example.
Car.find_by(number: 1).update(replacement_information_for_car_1.attributes.except(:id))
That's a long line that can be refactored to something like
new_attributes = replacement_information_for_car_1.attributes.except(:id)
Car.find_by(number: 1).update(new_attributes)
Im completely new to Ruby on Rails. Im working on an existing API and I have a sql query which is executed with:
results = ActiveRecord::Base.connection.select_all(query)
The output of the results is:
{"availability"=>"In Stock", "available_to_purchase"=>1}
{"availability"=>"Void", "available_to_purchase"=>0}
{"availability"=>"Out of Stock", "available_to_purchase"=>0}
{"availability"=>"In Stores Only", "available_to_purchase"=>0}
I know want to get all values for availability based on available_to_purchase being 0. I have tried:
res = results.where(available_to_purchase: 0)
But I get an error saying:
undefined method `where'
I also tried:
res = results.select { |result| result.available_to_purchase == 0 }
But i end up with the error:
undefined method `available_to_purchase'
I know I can loop through and check available_to_purchase is 0, then add to a new array. But is there any method to quickly filter active record results based on value of a column?
Going directly through the connection avoids nearly everything ActiveRecord is intended to provide you. First thing, read Active Record Basics. The Rails guides are really well put together and should contain everything you need for your first few weeks using the framework.
The reason you aren't getting the where method you expected is that it's a method on ActiveRecord::Relation, and select_all just returns you a list of hashes. By the time you call results.where, it's too late. You need to instantiate a Product model (or whatever would match your table name), which is as simple as:
class Product < ActiveRecord::Base
end
Rails will look at the products table (again, I'm making up your table name) for the attributes a Product has, and then you'll be able to query based on them with where:
results = Product.where(available_to_purchase: 0)
The model will also have the accessor methods you were trying for, so you can do things like results[0].available_to_purchase == 0 or results[0].availability = 'Already in your house'.
In order to call .where on the results, you need an instance of an active record relation. Regular ActiveRecord queries will return this. select_all, however, returns an array of hashes. Array does not have the method where.
res = results.select { |result| result.available_to_purchase == 0 }
Your second error is because you are attempting to access ruby hash keys incorrectly. Properties must be accessed asresult['available_to_purchase']
Here is the answer to your question. I do agree with others though that you should be using ActiveRecord.
results.select { |result| result['available_to_purchase'] == 0 }
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.
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 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