Ruby on Rails where() - ruby-on-rails

I'm doing my ruby project but i got a problem.
I have a problem on where in ruby like below.
#talk = Talk.where(params[:ask])
I get
"#<Talk::ActiveRecord_Relation:0x007f811404dae8>"
this from #talk.
I'm finding the value of the answer in my db with ask.
How can I print the value of the talk with where()?

If you have distinct ask values in your talk objects then you can do
#talk = Talk.find_by(ask: params[:ask])
which will return a single talk object. If no such ask value can be found nil is returned.

The objects are only retrieved when special methods like first, each etc are called. This is called lazy loading.
#talk = Talk.where(params[:ask])
#talk = Talk.where(params[:ask]).first
This way you will get the first entry which will be returned by your where, you can read some more about the lazy loading vs eager loading on this thread

where() will return a collection object. You are missing a column name with it.
If you want to access one object from the collection, use
#talk = Talk.where(column_name: params[:ask]).first #Or Talk.where(column_name: params[:ask]).last depending on the requirement
If you want to access all objects, you will have to loop through every object returned,
#talks = Talk.where(column_name: params[:ask])
-unless #talk.nil?
#talks.each do |talk|
= talk.column_name

Related

filter active record results in ruby

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 }

Active record where query for value inside of an array

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?

Why does a single record lookup return an array? (Rails beginner)

I have a where operation on a model that returns a single object. But I can't seem to use it in object notation (it appears to return an array with the object at [0]).
store = Store.where("some_id = ?", some_id)
puts store.name # doesn't work
puts store # shows array with the object at [0]
Because sometimes you don't know how many objects a query should return, so for consistency you always get an array.
To get a single object use
store = Store.where("some_id = ?", some_id).first
If you are looking for the primary ID of the model, you can also use
store = Store.find(some_id)
which will raise a RecrodNotFound exception (handled by rails as a 404 by default) if it doesn't find the object.
There are also dynamic finders
Store.find_by_some_id(some_id)
They are equivalent to
Store.where(:some_id => some_id).first
Where clause in rails 3.x will always return and arel objec, which you can use for method chaining.
Thus return statement of the where clause is always an array.
For accessing the first element you have to do
object.first as suggested by Jakub

Rails difference in object created from a .find(:id) and .where() methods

What is the difference in the objects created with these 2 methods:
tec = Technique.find(6)
tec2 = Technique.where(:korean => 'Jok Sul')
The data returned for each is exactly the same, yet the first object will respond perfectly to an inherited method like update_attributes while the second object will give an error of method not found.
When I do tec.class and tec2.class one is an ActiveRecord::Relation and the other doesn't give me a class at all, it just prints out the content of the object.
Maybe when you use the .where method you get an array, even if there is only one match and therefore you always have to issue the .each method to get at the contents? But that makes it hard to deal with when you want to update records, etc.
Can someone clarify this for me? Specifically, how to deal with matches found through the .where method.
Thanks.
Try:
tec2 = Technique.where(:korean => 'Jok Sul').first
Good question.
tec_scope = Technique.where(:korean => 'Jok Sul') # create an internal query
Remember, here only the query is created, it is not executed. You can programmatically build on top of this query if you so wished. The scope (or query if you so wish) will be executed in 2 ways. "Implicit" or "Explicit". Implicit way of running the query happens for example in the console, which invokes a method on the scope which automatically runs the query for you. This wont happen in your controllers unless you run it explicitly for .e.g
tec_scope.all # returns array
tec_scope.first # retuns one element
Scopes are just adding where clauses/predicates to your query. It's query building and delaying the execution till it is needed.
However,
tec_objects = Technique.find(6) # explicitly runs a query and returns one object (in this case)
This will explicitly run the query there and then. It is a question of the timing of execution of the query.
The difference is subtle but very important.
This hasnt got anything to do with whether you get one result or an array.
Technique.find([4,5]) # will return an array
Technique.find(4) # will return one object
Technique.where(:some_key => "some value").all # will return an array
Technique.where(:id => 5).first # will return one object
The difference is in timing of the execution of the query. Don't let the console fool you into believing there is no difference. Console is implicitly firing the query for you :)
The find(6) returns a single object, because you're specifying the object ID in the database, which is guaranteed to be unique by convention.
The where call returns a collection, which may be only 1 item long, but it still returns a collection, not a single object.
You can reveal this difference. Using your example code, if you call tec.class vs. tec2.class I think you'll find that they aren't the same class of object, as you expect.
That is, the methods available to a collection of objects is different than the methods available on an instance of that object.

Trouble on finding a class object in a array of classes

I am using Ruby on Rails 3.0.7 and I would like to understand how to handle the following code in order to retrieve a class objects with a specified id.
In my view file I have:
#records = Users.all # This returns an array (class)
In another file, a partial template, I would like to retrieve, for example, the user with id 1, but if I make this:
#records.find(1)
I get an enumerator (class) of all records:
<Enumerator: [<Users id: 1, ... ] >
How can I find the user with id 1 (or other ids) "a là Ruby on Rails Way"?
UPDATE
I use #records = Users.all in a view file because I aim to minimize calls to the database since I need to iterate almost over all records and check them existence. If I do for example:
some_hash.each { |key, value|
put User.find(value)
}
and I go in the log file, I will see a lot of database requests.
Even though this is probably quite slow, and I suspect there are some less than optimal designs in the app you're working on (not judging, we've all been there), Array#index seems to be what you're looking for:
#records[#records.index{|user| user.id == 1}]
Edit
Although if you need to do something for every user, and you need to access them by id quickly, I'd probably do something like this in your controller. Even if it's not really faster, it's much more readable (to me anyways):
#users_hash = {}
User.all.each{|user| #users_hash[user.id] = user}
Then in your views you can do:
#users_hash[id].username
Use User.scoped instead of User.all. #all will immediately query the database and return an array, whereas #scoped will return an ActiveRecord::Relation object which you can chain further queries. In this case, the database won't be hit until you try and somehow inspect or enumerate the result
Actually you're mistaken. #records.find(1) is returning an object of the class Enumerator (which is not the same as the class Enumerator itself).
The problem here is that, as you've noted, #records is an Array, not an ActiveRecord object, and Array#find (inherited from Enumerable#find--which, when not given a block, returns an object of class Enumerable) is not the same method as ActiveRecord::Base#find (i.e. User#find).
What you should do is, in your controller, pick out the one user record you want:
#user = User.find 1
...and then use #user directly in your template. Generally you should avoid doing ActiveRecord lookups (e.g. find) in your templates. That kind of logic should happen in your controller.
Last time for such case I ended up doing like this:
#assignments = Assignment.find_by_sql(' ... ')
#assignments.find(id: 1).first

Resources