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
Related
I need all the documents in one of my collections to create association in between my parent model to child. The problem is I only have the string of my ObjectId. So I am finding the object by string and then set via parent.child = foundObject. So, to achieve this I created a private method as below, to not to create DB request each time I need that child object.
def childs
#childs ||= Child.all
end
But this is not working as expected. When I run ModelName.all it returns below result; not all the docs in collection.
=>
#<Mongoid::Criteria
selector: {}
options: {}
class: ModelName
embedded: false>
And this causes my loop to create another DB request each time I try to associate child to parent. I prevent this by using below method.
def childs
#childs ||= Child.all.select { |v| v.id.present? }
end
I believe there should be a way of collecting all documents in MongoDB, I know the idea of Mongoid::Criteria and what it actually does. But in some case, I need all the objects to be stored in one variable. Do not want to create unwanted DB queries each time I need one specific document in a model.
I could not find a way to solve this specific problem and I think it's kind of impossible since MongoDB is not a relational DB It's quite hard to collect information at the same time with querying. What I used is "MongoDB views" and this solved a lot. Here is the docs. There you can read and find yourself an approach to figure out your own problem.
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
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
#category = Category.where(:category_name => 'cricket')
#category.class
Here the class of #category is "ActiveRecord::Relation"
But,
#category = Category.all(:conditions => { :category_name => 'cricket' })
#category.class
In this case the class of #category is "Array"
The result of both the queries are same, then also the class is different.
WHY?
One more thing...
In the first case, I can do #category.title or #category.body etc.
But in second case, It is not possible.
WHY?
In the first case you are actually using the default scope and attribute it with the where part. It means, when you want to use the items of this Relation, it will run the SQL query on demand. Think about it like it is prepared, but not yet ran query, which will yield walues when needed, and you can further specify the parameters, for example you can append another where clause, or something to it. And of course it is smarter than a simple array, because of the implementetion is more complex behind this.
In the second case you immediately fetch all record from the database, so the result is an Array, containing the results. It is pretty dumb compared to the other one.
I have array of objects. I can't store it in DB for performance reason. I tried store array in Global ($var) and Class (##var) variables (in controller), but it was the same array for all users. It should be unique for each user session and in each session it should be able to be modified quickly.
I understand that the session[] - is not the best solution. What is the best way?
I'm doing something like this $lines_rules << Processing::rule_creator(...) in every time, when run action in controller.
$lines_rules - it is my array of objects.
Why DB is not right for store $lines_rules? In $lines_rules I store objects with lambda function. When user press button I need call every lambda function with user input and keep result. Then I load new objects into $lines_rules. Thus every request change $lines_rules. I think work with memory is the better way for perfomance.
UPDATE
I use $global_hash [ session[:session_id] ] and this technique for resource saving:
def dead_sessions_killer
ActiveRecord::SessionStore::Session.where(["updated_at < ?", 30.minutes.ago]).each do |session|
$global_hash.delete_if {|key, value| key == session.session_id }
session.delete
end
end
Use a global, but a global hash, keyed by the user's session id.
Store whatever you want in there, although with proper caching, hard to say if this is a great idea.
You could declare the array as a class variable (only 1 # sign), and provide an accessor method.
That is:
class Foo
#some_array
def some_array
#some_array
end
end
From other classes, this lets you call foo_instance.some_array, which keeps the array specific to the user, but allows public access from any class.
You could store the user session in memory with memcache. That would be convenient and fast.
http://awesomerails.wordpress.com/2011/08/23/rails-3-memcached-session-store/