proxy_reflection equivalent on ActiveRecord::Base#find? - ruby-on-rails

I'm trying to make a helper which automatically picks the correct partial based on the types of objects returned by either ActiveRecord::Base#find or an association. Unfortuneatly I can't just look at the first element of the returned array because I want to pick the correct one in this case as well. If you call an association, it returns a proxy with the proxy_reflection method, which is exactly what I want, but it doesn't exist on the result of ActiveRecord::Base#find :(.
Example:
association_posts = Author.find(1).posts
association_posts.proxy_reflection.class_name # Returns "Post"
all_posts = Post.find(:all)
all_posts.proxy_reflection # no method exception, what do I call here instead?

I'm not sure if this is what you want, but try:
all_posts.first.class

Related

How to get active record's name after using find .where

Straight forward here:
<% #yyy = CityRace.where(city_race_id2: "3") %>
<% #xxx = #yyy.name %>
The #yyy is returning the proper record using the ID I have passed into it, but I'm trying to get the objects name. For some reason .name isn't working. Any idea what I'm going wrong here?
How do I find a record's name where id = a certain id?
where returns an ActiveRecord_Relationship, meaning an object containing CityRace objects for every row in the database with city_race_id2 equals to 3, no matter if there's only one, the result is an ActiveRecord_Relationship object, and that doesn't respond to name.
If you need the name of a particular object from that result, you can access to the specific element by its index and invoke name on it, e.g:
CityRace.where(city_race_id2: "3").first.name
Or to retrieve the name from every object:
CityRace.where(city_race_id2: "3").pluck(:name)
this one returns an array of strings, so, you must iterate over them to print them all or get a specific one.
In the other hand if you need a single row from the query, use find_by:
CityRace.find_by(city_race_id2: "3").name
.where returns an ActiveRecord::Relation which behaves like an array. You can think of it like a special kind of array that allows you to chain on more active record queries on it. When you call certain methods like each or to_a it evaluates the query into an actual array.
In any case, what you are looking for here is not something array-like. You want #yyy to refer to a single record.
Simple fix, just use find_by instead of where. Also take a look at https://api.rubyonrails.org/classes/ActiveRecord/FinderMethods.html#method-i-find and find vs find_by vs where

How to update table row from values determined within controller

ruby_on_rails rails 4 assignment non-screen data to insert record
Rather than using screen values (e.g. simple_form_for #user_evaluation_result) to populate the columns to insert a row I need to calculate some of the values in controller.
For example if I have these statements in the controller
….
# which if I had simple_form_for user_evaluation_result would get populated by the screen
#user_evaluation_result = UserEvaluationResult.new(user_evaluation_result_params)
….
# standard stuff I use for screen derived updates
def user_evaluation_result_params
params.require(:user_evaluation_result).
permit(:evaluation_assumption_id,
:company_listing_id,
:target_share_price_dollars )
end
How do I assign values to :user_assumption_id etc so that insert works. I have tried all sorts of statements. Alternatively do I use another format instead of calling "def user_evaluation_result_params".
Thanks in advance - Pierre
I'm hoping I've interpreted the question properly...
First, to make sure we're on the same page... The code inside of your user_evaluation_result_params method is using Strong Parameters to create an ActionController::Parameters object for the purpose of protecting your model from unpermitted mass-assignments. So, in general, when you're creating or updating an ActiveRecord object from a form in a view template, you want to use Strong Parameters so that users can't manipulate your form to set attributes that you're not expecting.
That said, if you want to set attributes on an object you don't have to use mass assignment. Here is an example of using one-at-a-time assignment (the opposite of mass-assignment):
obj = MyObject.new
obj.attr_one = "One"
obj.attr_two = "Two"
obj.save
There is nothing wrong with this approach other than that it's kind of a lot of work for the general case. So mass-assignment just saves us from having to do this all the time. But it sounds like this one-at-a-time assignment is what you're wanting in this case. So try something like this:
def create
#user_evaluation_result = UserEvaluationResult.new
# assuming you have a UserAssumption object instance in `my_user_assumption`
#user_evaluation_result.user_assumption = my_user_assumption
#user_evaluation_result.some_other_attr = "some value"
#user_evaluation_result.save
end
Note, instead of setting #user_evaluation_result.user_assumption_id directly, as you asked about, it is preferred to set the actual object association as I did above. Try to keep associations outside of mass-assignment and use object relationships to build up your object graphs.
Or, if you have some attributes coming from a form you can mix and match the two approaches:
def create
#user_evaluation_result = UserEvaluationResult.new(user_evaluation_result_params)
# assuming you have a UserAssumption object instance in `my_user_assumption`
#user_evaluation_result.user_assumption = my_user_assumption
#user_evaluation_result.some_other_attr = params[:user_evaluation_result][:some_other_attr]
#user_evaluation_result.save
end
private
def user_evaluation_result_params
params.require(:user_evaluation_result)
.permit(:evaluation_assumption_id,
:company_listing_id,
:target_share_price_dollars)
end

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?

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