This is a question I've long wanted answered by never bothered to ask as I found other ways.
In my Index action for a controller - I have this line:
@all_pos = PurchaseOrder.where(:merchant_id => session[:admin_id], :received => false).sort([sort_column,sort_direction])
So I get a Plucky query at this point - the results haven't been grabbed, just locked a cursor (I get this part).
What I want to do though is modify this @all_pos object (hash) in place before I send it up to the view.
Why?
Because I've done some relational stuff (gasp) where I'm storing an ObjectId as one of the values inside this object.
:po_vendor is stored as the ObjectId that points to the document describing vendors. I didn't want to use MongoMapper's "belongs_to" feature (for whatever reason I don't recall - i just didn't), so when I render my view, if I want to call @all_pos.po_vendor I'm going to print an ObjectId on the page. No bueno.
Now I could look up the document from the view - but that's not very Railsy!
So what I want to do is modify each of the elements inside the @all_pos array-hash.
@all_pos.each do |po|
vn = Vendor.find_by_id(po.po_vendor).name
po.po_vendor = vn
end
In my head the above works - I access the po_vendor key and set it's value. But it's not filtering up into the @all_pos, and the biggest problem is I don't have the Rails vocabulary to describe what I'm trying to do here.
map! ? collect! ? I could Google and figure it out if I knew the words to describe this :(
use association to solve your problem in your PurchaseOrder
model add association for Vendor
class PurchaseOrder < ActiveRecord::Base
belongs_to :vendor, foreign_key: :po_vendor
delegate :name, to: :vendor, prefix: true, allow_nil: true
...
...
...
end
in controller
@all_pos = PurchaseOrder.includes(:vendor).where(:merchant_id => session[:admin_id], :received => false).sort([sort_column,sort_direction])
And then, in View you can use
@all_pos.each do |po|
po.vendor_name
end
The main problem is that as assigned, @all_pos is a query and NOT documents resulting from the query. On iteration of the query, you look up purchase orders and then the vendors, but you don't have a variable handle to reference the fetched purchase orders (@all_pos still just references the query, not the fetched docs), and without references, you can't get to them, and they'll be garbage collected.
The following test is what I think that you want, with two examples. The first does individual vendor db finds as in your question. The second creates a local Hash for lookup from a single common db find for the vendors for efficiency.
test/unit/purchase_order_test.rb
require 'test_helper'
require 'pp'
class PurchaseOrderTest < ActiveSupport::TestCase
def setup
PurchaseOrder.delete_all
end
test "the truth" do
puts "\nMongoid::VERSION:#{Mongoid::VERSION}\nMoped::VERSION:#{Moped::VERSION}"
session = {admin_id: 1}
sort_column = :merchant_id
sort_direction = 1
@query = PurchaseOrder.where(:merchant_id => session[:admin_id], :received => false).sort([sort_column,sort_direction])
assert_equal(Mongoid::Contextual::Mongo, @query.class)
vendor = Vendor.create(name: 'Amazon')
PurchaseOrder.create(merchant_id: 1, received: false, po_vendor: vendor._id)
@all_pos = @query.to_a
assert_equal(PurchaseOrder, @all_pos.first.class)
@all_pos.each do |po|
po.po_vendor = Vendor.find(po.po_vendor).name
end
puts "with individual vendor db find:\n#{@all_pos.inspect}"
@all_pos = @query.to_a
vendors = Vendor.find(@all_pos.collect{|po| po.po_vendor})
vendor_hash = Hash[*vendors.collect{|v| [v._id, v.name]}.flatten]
@all_pos.each do |po|
po.po_vendor = vendor_hash[po.po_vendor]
end
puts "with single common vendor db find:\n#{@all_pos.inspect}"
end
end
rake test
Run options:
# Running tests:
[1/1] PurchaseOrderTest#test_the_truth
Mongoid::VERSION:3.1.6
Moped::VERSION:1.5.2
with individual vendor db find:
[#<PurchaseOrder _id: 535803b87f11ba5720000002, merchant_id: 1, received: false, po_vendor: "Amazon">]
with single common vendor db find:
[#<PurchaseOrder _id: 535803b87f11ba5720000002, merchant_id: 1, received: false, po_vendor: "Amazon">]
Finished tests in 0.040748s, 24.5411 tests/s, 49.0822 assertions/s.
1 tests, 2 assertions, 0 failures, 0 errors, 0 skips
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.