I have a structure that has both :id and a :group_id fields. I wish to retrieve all the data which :id equals :group_id.
I am currently working with mongoid, but I think that the operation is done the same way as it would be done when using Rails3's ActiveRecord.
Anyways. I was trying to use Message.where(:group_id => :id), which should return, for instance, this: => #<Message _id: 4e38aa132748440a7e00007d, group_id: BSON::ObjectId('4e38aa132748440a7e00007d')>. But it does not work at all (it seems as if it really should not work, but how it should, then?)
How can I query mongoid (or active record) to get only the Messages where :id equals :group_id?
EDIT:
just to show that those values are really exactly the same:
ruby-1.9.2-p180 :088 > Message.first.id
=> BSON::ObjectId('4e38aa132748440a7e00007d')
ruby-1.9.2-p180 :089 > Message.first.group_id
=> BSON::ObjectId('4e38aa132748440a7e00007d')
EDIT2:
These do not work (they have at least one message (the example above) that match)):
ruby-1.9.2-p180 :091 > Message.where("group_id = id").count
=> 0
ruby-1.9.2-p180 :092 > Message.where("group_id == id").count
=> 0
EDIT3:
Here is an example of message that should be returned: http://cl.ly/3q1r20421S3P1921101D
EDIT4:
Another piece of weirdness:
ruby-1.9.2-p180 :034 > Message.where("this._id = this.group_id").each {
|m| puts "#{m.id} = #{m.group_id}" }
4e38aa132748440a7e00007d = 4e38aa132748440a7e00007d
4e38aa132748440a7e00007e = 4e38aa132748440a7e00007d
4e38aa562748440a7e000084 = 4e38aa562748440a7e000084
4e38aa562748440a7e000085 = 4e38aa562748440a7e000084
4e38ac312748440a7e000095 = 4e38ac312748440a7e000095
4e38ac312748440a7e000096 = 4e38ac312748440a7e000095
4e38ac312748440a7e000097 = 4e38ac312748440a7e000095
Why it returns those values, even though in some cases they are not equal? Aaaarghhhhh
EDIT5: Another piece of weirdness and a small inconclusive conclusion:
ruby-1.9.2-p180 :090 > Message.where("this.read == this.sender_deleted").each {
|m| puts "#{m.read.to_s},#{m.sender_deleted.to_s}" }
true,true
false,false
false,false
false,false
false,false
My query works with boolean values! Hence, it SEEMS it is not working only with BSON::ObjectId() object comparisons (I also could not retrieve messages by doing Message.where(:id => Message.first.id [edit: I managed to do this by using :_id instead of :id, but this did not help me on the remaining of my problems]). How can I compare these damn identifiers on the same object? I really need to, and I am afraid there is no elegant alternative (storing those exact same IDs as strings would be just too weird, please do not suggest it :/ ). In the end, this seems like a specific issue to Mongoid.
obs.: I tried all combinations that came to mind, regarding id vs. _id and = vs. ==. Is there any Hash-like query for accomplishing what I need? using something like .where(:_id => :group_id) (but not that, I mean the :group_id value, not a :group_id symbol).
Try this:
Message.where("this.group_id == this.id")
Mongoid usees MongoDB in the end, so anything which is not possible in mongodb can not be done using mongoid. The particular use case you are talking about, is not supported by mongodb as of now.
You cannot query a field against a field, you have to provide literal values to query against. I saw an issue on Mongodb Issue Tracker for supporting this, but couldn't locate it now.
The boolean value query you are mentioning, might just be a coincidence. That should also not work as expected.
Update
One can compare fields in mongodb using $where clause.
You have been missing the '$where' in Mongoid's where method
This worked for me:
Message.where('$where' => 'this.group_id == this.id')
Message.where("group_id = id")
Related
This is an existing code written by someone else and am trying to enhance it. I am a java developer working on Ruby on Rails, so kindly be considerate.
I have entities like this
User
Delivery entity,
Delivery
belongs_to :user
named_scope :for_abcs, :conditions => {'deliveries.xyz_type' => ['Xyz1', 'Xyz2']},
many such named-scopes are defined.
Now to fetch the deliveries its written like this
#deliveries = current_user.deliveries.send("for_abcs").with(:xyz, :sender, :receiver)
...
...
...
# few other conditions added to #deliveries
finally
#deliveries.sort(...)
This sort is taking huge sql and giving performance issues. I want to use find_each, but find_each is only for Active Entity in Ruby on Rails, How can I achieve this (if possible) without much code change)
Earlier I used to do
Delevery.find_each
wherever it is
Delivery.find
Now I cant do as it is an array, what is the workaround or right procedure to do that in Ruby on Rails.
EDIT :
What I tried :
deliveries_temp = []
#deliveries.find_each(:batch_size=>999) do |delivery_temp|
deliveries_temp.push(delivery_temp)
end
This gave me error
undefined method `find_each' for []:Array
type(#deliveries) returned ActiveRecord::NamedScope::Scope , rails version 2.3.18
find_each should work on anything that returns a Relation (which includes scopes).
#deliveries = current_user.deliveries.for_abcs(:xyz, :sender, :receiver).find_each
Update
It sounds like you're using Rails 2.3. find_each is a class method in 2.3, so you'll need a way to extract the conditions from your scope and pass them to find_each. I found an article that looks promising, so give this a try:
Delivery.find_each(current_user.deliveries.for_abcs.scope(:find))
Also, I'm still not sure what that #with is doing. Maybe it's supposed to be #includes?
After lot of research for a week and learning about named_scopes by checking its source code. I understood what the problem was. The #deliveries is an object of class ActiveRecord::NamedScope::Scope . This class do not have find_each method. So I wrote a new named_scope for limit and offset in Delivery model file as follows :
named_scope :limit_and_offset, lambda { |lim,off| { :limit => lim, :offset=>off } }
After this , I called it in a loop passing offset and limit , for ex. first loop has offset=0, limit=999 , second loop has offset=999, limit=999 . I will add all the results into an emptry array. This loop continues till the result size is less than the limit value . This is working exactly the way I wanted , in batches.
set = 1
total_deliveries = []
set_limit=999
original_condition = #deliveries
loop do
offset = (set-1) * set_limit
temp_condition = original_condition.limit_and_offset(set_limit,offset)
temp_deliveries = temp_condition.find(:all)
total_deliveries+= temp_deliveries
set += 1
break if temp_deliveries.size < set_limit
end
#deliveries = total_deliveries.sort do |a, b|
The answer on this question has provided me with a nice roadmap for how to generate select tags with data from a collection on an association.
This works nicely and everything is going great.
The issue I have now is, how do I handle an empty collection?
With the regular :type => :input, I can just specify :nil => "Some nil message here".
But that doesn't seem to work for the collection, and to make matters worse, when there is nothing in the collection it seems to be displaying some integers (i.e. 1 and 2). I am assuming those are the IDs from the previously displayed objects in the collection, but for obvious reasons that doesn't make much sense.
Any ideas on how I can handle an empty collection with this gem?
Thanks.
Edit 1:
One alternative is to just put my original best_in_place helper tag inside an if statement for when a collection is not nil. But then how does the user edit it when it is blank? Perhaps there may be no way to handle this, because it would involve creating a new record in the collection.
I use a "workaround" for the empty options in a select tag, it could help you:
:type => :select, :collection => #my_colletion || [[I18n.t('common.none'), -1]]
When #my_colletion is nil, it shows a choice named 'None' with id = -1 (wich is not that bad to handle in the backend).
This part of code assumes the #my_collection is an array of arrays like [ [key, value], [key, value], ... ] OR nil.
Although, if you want your MyModel.all collection to fit the conditions for best_in_place, you can use the following:
#my_collection = MyModel.all.map{ |object| [object.name, object.value] }
# => this returns an array like [ [key, value], [key, value], ... ]
# => returns an empty array (NOT nil) if there is no entry in the DB
About the -1 id:
Using the -1 id as 'none' is easy because you don't need to explicitly handle the value nil (tests, etc). With the -1 id, you can use the following:
MyModel.where(id: params[:id]).first # => Returns the first object that has the params[:id]
# if params[:id] is -1, it will return nil and not raise an error.
I hope it helped :)
Current Code
#current_site_name = 'SITENAME'
#current_site = Site.where(:name => #current_site_name)
#current_site_id = #current_site.id
Basically, the name column in our Site model is unique. We are selecting a row using the site name as a parameter.
I am returned: <ActiveRecord::Relation:0x59426bc1>
I understand that I cannot simply ask for #current_site.id but is there any way to put the ID of the single activerecord into the variable #current_site_id
Again, there will always be one active record.
As you've seen, where will return an ActiveRecord::Relation (a set of rows), even if there's only one row that matches your criteria. You can make #current_site be assigned to the row you want by changing the line to this:
#current_site = Site.where(:name => #current_site_name).first
Hmm... This is quite strange.
Site.where(:name => #current_site_name).methods.include? :id #=> false
but
Site.where(:name => #current_site_name).instance_methods.include? :id #=> true
However,
Site.where(:name => #current_site_name).instance_eval "id" #=> NameError
and
Site.where(:name => #current_site_name).methods.include? "self.id" #=> NoMethodError
That said, a workaround assuming in your case, only one record should be returned is
Site.where(:name => #current_site_name).instance_eval('find_first').id
The find_first method is protected so we have to jump scope in its execution to avoid another NoMethodError
Just to throw another solution out there, you can make use of Rails' dynamic finders that are created for your models.
#current_site = Site.find_by_name(#current_site_name)
This returns a single record (and thus doesn't require the use of first) and might be seen as cleaner code in some people's opinion.
In my view page, i am using form_tag to create a form which will pass a string of ids from a hidden field to the controller code.
In my controller code, i am looping through an array of ids to update each record containing that id in the Expression table. But the code below does not seem to work.
I would really appreciate it if somebody could give me some suggestion regarding what is wrong with the code below.
def update_expression
#emi_ids_array = params[:emi_ids].split(/,/)
#sub_id = params[:sub_id]
#emi_ids_array.each do |emi_id|
#existing_exp = Expression.find(:first, :conditions => [ "EXT_EMI_ID = ? and EXT_SUB_FK = ?", emi_id, #sub_id])
#expression = #existing_exp.update_attributes(
:EXT_SUB_FK => #sub_id,
:EXT_PRESENCE => "present",
:EXT_STRENGTH => "weak",
:EXT_EMI_ID => emi_id
)
end
end
Try converting the array of ID's (and the sub_id) to integers.
Is it the finding of the object that fails, or the update? Output the #expression.errors after the update call to see if there are any validations failing.
Is there a reason for all the instance variables? You don't need the #'s if the variable doesn't go beyond that method. Also the #expression item seems superfluous, you're just duplicating the #existing_exp object, you don't need to put the return into a new object, especially if it's replaced each time the loop runs anyway.
Found a temporary solution. 'update_attributes' does not seem to work, so i opted for 'update_all' attribute
Expression.update_all({:EXT_PRESENCE => "present", :EXT_STRENGTH => "weak"},['EXT_EMI_ID = ? and EXT_SUB_FK = ?', emi_id, #sub_id])
Hopefully, it might be useful to someone else
I have a service I query and I get data I filter through and create a an array of records.
Unless I missed something, ActiveResource::Base does not qualify since the access to the service is not via rest and I can't use the raw data as delivered.
I am displaying the data in a table and use will_paginate to page the data. But I am not currently married to will_paginate.
I do need to sort the columns as well as paginate.
I have found two version of ujs_sort_helper.
https://github.com/pengwynn/ujs_sort_helper
https://github.com/sikachu/ujs_sort_helper
I am trying to understand:
- http://javathehutt.blogspot.com/2009/06/mo-simple-sortable-tables-in-rails.html
What have other done in rails 3? Or is one of the ujs_sort_helper packages just he correct way to go.
In term of data refresh, this is a dashbaord. Multiple data source will address the various DIVs.
Also, I am a Rails noob. But not a programming noob.
You could use meta_search's sort_link if you wish.
I like it because it also does filtering incredibly easy with meta_where.
You can also make the behavior through ajax by adding the data-remote attribute to 'a.sort_link' (i have done that through javascript).
I would welcome the maintainer of ujs_sort_helper to comment. Just a bug here and there in the rails 3 version of the code. Now ujs_sort_helper works, for me.
What I have not done is create ANOTHER branch on this package. I emailed the file to the author.
sort order now compares symbols, instead of symbol to string.
def sort_order(column, initial_order='asc')
#safe since to_sm on a sym is a nil operation. At least for now.
if session[#sort_name][:key].to_sym == column.to_sym
session[#sort_name][:order].downcase == 'asc' ? 'desc' : 'asc'
else
initial_order
end
end
The icon us set via the current order value. The sort clause should be the opposite. So show down arrow for the list being displayed in ascending order, but the 'url' is set to redisplay the table in descending order.
I have no clue what the :q symbol is supposed to be used for.
def sort_header_tag(column, options = {})
options[:initial_order].nil? ? initial_order = "asc" : initial_order = options[:initial_order]
key = session[#sort_name][:key].to_sym
order = sort_order(column, initial_order)
caption = options.delete(:caption) || column.to_s.titleize
url = { :sort_key => column, :sort_order => order, :filter => params[:filter]}
url.merge!({:q => params[:q]}) unless params[:q].nil?
content_tag('th', link_to(caption, url, :class=>session[#sort_name][:order] ), :class => "sort_link #{order if key == column}")
end