Ember model only loads last record - ruby-on-rails

I'm trying to reproduce Railscasts 410 example (called Raffler), changing the setup for last versions and to match my habits:
Ember 1.0.0-rc.6
Rails 4.0.0
Mongoid master (4.0)
Haml 4
Emblem 0.3.0
In this example project, we create a simple model Entry that calls a small Rails Rest API.
Everything works as expected, except that calling Raffler.Entry.find() to get all entries only loads the last record.
Here is my model :
Raffler.Entry = DS.Model.extend
name: DS.attr('string')
winner: DS.attr('boolean')
My store :
DS.RESTAdapter.configure('plurals', entry: 'entries')
Raffler.Store = DS.Store.extend
revision: 12
adapter: DS.RESTAdapter.create()
When calling Raffler.Entry.find() there's an AJAX request on http://localhost:3000/entries and all records are returned (so I don't think the problem is server side) :
{"entries":[{"id":{"$oid":"51e5b35b492cd4d286000001"},"name":"Foo","winner":true},{"id":{"$oid":"51e5b35b492cd4d286000002"},"name":"Bar","winner":false},{"id":{"$oid":"51e5b384492cd4d286000003"},"name":"Baz","winner":true}]}
But only the last of these records is really loaded in the model.
Here in the JS console :
e=Raffler.Entry.find()
e.toArray().length
=> 1
e.objectAt(0).get('name')
=> "Baz" (always the last one)
e.objectAt(1)
=> undefined

I've finally found the cause of the problem (thanks to this question): it was because, by default, Mongoid returns JSON with id in the format {"id":{"$oid":"51e5b35b492cd4d286000001"}, that Ember does not seem to understand.
By adding this serializer on my Rails Entry model:
class EntrySerializer < ActiveModel::Serializer
attributes :id, :name, :winner
def id
object._id.to_s
end
end
API request now responds this (note there's no $oid anymore):
{"entries":[{"id":"51e5b35b492cd4d286000001","name":"Foo","winner":true},{"id":"51e5b35b492cd4d286000002","name":"Bar","winner":false},{"id":"51e5b384492cd4d286000003","name":"Baz","winner":true}]}
and Ember now loads all records :
Raffler.Entry.find().toArray().length
=> 3
EDIT: Note that this is a Mongoid 4 specific issue since the $oid notation wasn't used in earlier versions. Here is a test with an existing Rails 3.2 / Mongoid 3.0 app :
1.9.3-p194 :006 > Mongoid::VERSION
=> "3.0.23"
1.9.3-p194 :007 > Node.first.id.as_json
=> "507521e68df996381b00151b"
Now with my Ember test under Rails 4 / Mongoid 4 :
2.0.0-p247 :007 > Mongoid::VERSION
=> "4.0.0"
2.0.0-p247 :008 > Entry.first.id.as_json
=> {"$oid"=>"51e5b35b492cd4d286000001"}
I've added the mongoid tag to my question.
The Serializer solution works well but it means creating a serializer for every single Mongoid model...just to return to Mongoid 3 behavior...not that clean...

You have posted that Raffler.Entry.find() returns this :
{"entries":[{"id":{"$oid":"51e5b35b492cd4d286000001"},"name":"Foo","winner":true},{"id": {"$oid":"51e5b35b492cd4d286000002"},"name":"Bar","winner":false},{"id":{"$oid":"51e5b384492cd4d286000003"},"name":"Baz","winner":true}]}
than :
e=Raffler.Entry.find()
e.entries.length
=> 3
e.entries[0]
=> {"id":{"$oid":"51e5b35b492cd4d286000001"},"name":"Foo","winner":true}
e.entries[0].name
=> "Foo"
Whats the problem?

Related

Is there a known performance regression with querying/eager loading/instantiating AR objects in Rails 4.2.8?

We're recently upgraded our stack from Rails 3.22.5 to Rails 4.2.8. We have both a big CRUD application in Rails, and a Sinatra API app. They both are on the same Ruby versions (2.4.1), the same ActiveRecord and ActiveSupport versions, and share the same database (Postgresql) and all of the model files.
We've also upgraded the Ruby versions, but switching back to the old Ruby version did not change anything, so I'll keep talking about the setup as-is.
It looks like, since the upgrade, our API responses have become 40%-50% slower in the worst cases (the Rails app responses have also slowed, but not as much). This example looks at the worst case, where we query for 100-200 "Message" records which contain a quite deep eager loaded hierarchy of associated models, using also ActsAsList and STI relations. Here is how they're queried:
messages = property.
messages.
visible(property, opts[:days]).
includes(:translations).
includes(:gallery_images).
includes(:place).
includes(:property => :places).
includes(:address => [:translations, template: :translations]).
includes(:tags).
includes(:interests => :interest_disablings).
includes(:template => [
:translations, {:interests => :interest_disablings}, :gallery_images, :property, :tags, {:address => [:translations, template: :translations]},
{:template => [:translations, {:interests => :interest_disablings}, :gallery_images, :property, :tags, {:address => :translations}]}
]).
includes({current_availability: [:property, :timing, :capacity, { custom_booking_fields: :translations }]}).
includes(:availabilities).all.to_a
(The two nested :template references go to the same "messages" table, messages have two levels of "parent" templates. The "translations" come in via the Globalize gem)
Both this part (after which no more SQL calls are being made) and later processing (Hash/Array and Time/Timezone manipulation to build up an API response to be serialized to JSON) have slowed down.
When looking at RubyProf profiles before and after, I can see no obvious bottlenecks, except that it seems like there is more Arel/Association code happening now, but can't he sure of it.
I can also see similar slowdown by simply benchmarking this:
rails3:
>> Benchmark.measure { 1000.times { Message.find(187812) } }.total
=> 0.29000000000000026
rails4:
>> Benchmark.measure { 1000.times { Message.find(187812) } }.total
=> 0.5200000000000005
I can provide the profilings and any benchmarks, if needed.
Is this something that is known, i.e. were there tradeoffs being made in Rails and I'm now hitting a too-many-records case?
Update: I created blank Ruby on Rails apps each for the old (Ruby 2.3.1/Rails 3.2.22.5) and the new setup (Ruby 2.4.1/Rails 4.2.8), and copied the database.yml over to it so the blank apps use the same DB. Using also bare-bones model files (the originals have a lot of code), I still see a difference:
2.3.1 :009 > ActiveRecord::Base.logger = nil; Benchmark.measure { 1000.times { Message.find(133147) } }.total
=> 0.29000000000000004
2.4.1 :009 > ActiveRecord::Base.logger = nil; Benchmark.measure { 1000.times { Message.find(133147) } }.total
=> 0.41000000000000014

Rails cookies value different from controler with helper scope?

ENV:
Rails 3.2.15
ruby 1.9.3p194 (2012-04-20 revision 35410) [x86_64-darwin12.2.0]
I set cookies in controller and read it from helper method, and two result is not same. Why?
# in controller
cookies[:"position"] = { :value => [ 100,200 ], :expires => 1.years.from_now }
# read it same time, it display value is an array [100, 200]
# But I read this cookies in another request, it display "100&200"
# in helper
module WelcomeHelper
def get_position
cookies[:"position"]
end
end
```
get_position method return 100&200
Where can I find some documation? I found in code, it discribled array can be stored in cookies directly and read it directly: https://github.com/rails/rails/blob/v3.2.15/actionpack/lib/action_dispatch/middleware/cookies.rb#L45 , but why I stored an arry in cookies and result from read is a string?
If you want to use non-string values for your cookies please convert them to JSON first.
# using the preferred 1.9 hash syntax and no need to quote "position"
cookies[:position] = { value: JSON.generate([ 100,200 ]), expires: 1.years.from_now }
Check the Rails 4.1 documentation on Cookies.
Rails 3.2 documentation caused a slight confusion on that issue by implying that a Ruby array can be stored directly as a cookie value which was fixed recently by using JSON dump/load and subsequently by the safer JSON generate/parse.

ArgumentError recursive array join

Calling method "polymorphic_url" in controller or template with array as argument, like:
polymorphic_url([#agency, #agency.divisions.first])
causing ArgumentError exception named "recursive array join". Any suggestions?
I can reproduce this exception with any of models:
#e = Estate.where(:booklets => {'$exists' => true}).first
#b = #e.booklets.first
polymorphic_url [#e,#b]
rails 3.2.3, 3.2.4, 3.2.5
ruby 1.9.2, 1.9.3
You can create your Error with an Array which contains a reference to itself:
a = []
a<<a
a.join #ArgumentError: recursive array join
I'm guessing here, but if divisions points to the same array as #agencie( for instance an agency being it's own division) I can imagine something like above happening. May be it does not have anything to do with updates but with the data.
I believe you are misusing it. According to APIDock, here are some examples of polymorphic_url use:
# calls post_url(post)
polymorphic_url(post) # => "http://example.com/posts/1"
polymorphic_url([blog, post]) # => "http://example.com/blogs/1/posts/1"
polymorphic_url([:admin, blog, post]) # => "http://example.com/admin/blogs/1/posts/1"
polymorphic_url([user, :blog, post]) # => "http://example.com/users/1/blog/posts/1"
polymorphic_url(Comment) # => "http://example.com/comments"
So maybe you should use:
polymorphic_url([#agency, #division])
Im solve this issue by forcing application to use bson '1.6.2'
https://github.com/mongoid/mongoid/issues/2069

Undefined method 'zero' for ... ActiveSupport::OrderedHash

Check the note below. Why is it before I do p variant_attributes, blank? method returned error, while after it, it works fine?
Ruby 1.9.2-p0 on Rails 3.0.3
p variant_attributes.blank?
# => NoMethodError Exception: undefined method `zero?' for {"Brocade w/ Grande Stripe backing"=>3}:ActiveSupport::OrderedHash
p variant_attributes
# => [#<VariantAttribute id: 1251, variant_id: 561, product_option_id: 838, value: "Brocade w/ Grande Stripe backing">]
p variant_attributes.blank?
# => false
If variant_attributes is a kind of ActiveRecord collection of records (which it looks like) then it is probably because rails uses lazy loading to fetch records from the database but the blank? method does not trigger the actual loading.
You may want to call the all method on variant_attributes to manually trigger the loading, or if you don't want to do that, you may go for variant_attributes.count.zero? instead of variant_attributes.blank?
See Pratik Naik's blog post about ActiveRecord 3.0 query interface for the details

how to override [] brackets in ruby?

I am writing an Ajax request form with Ruby on Rails using a collection_select tag that looks like this:
<%= collection_select("Jobs", "clearance", #allClearances, "clearance", "clearance", {:prompt => "Select a Clearance"} )%>
Ruby then builds an HTML select tag with id = "Jobs_clearance" and name = "Jobs[clearance]"
I want to send the parameter to my controller, which looks like this:
class JobsController < ApplicationController
def foo
#clearance = params[:Jobs[clearance]]
end
Unfortunately, Ruby only reads ":Jobs" as the symbol instead of ":Jobs[clearance]"
Is there a way to escape the []'s? backslash isn't working.
kmorris solved your problem (very well) but i would like to answer your question:
you can override [] and []= operators because they are methods (like almost everything), but you should think well about what you are doing because you can break tons of things.
class AntiArray < Array
def [](ind)
self.fetch(-ind)
end
end
y = AntiArray.new([1,2,3,4])
y[1]
=> 4
You need to use params[:Jobs][:clearance]
params is a hash of all the request parameters. But params[:Jobs] is ALSO a hash of all :Jobs parameters. So calling params[:Jobs][:clearance] is calling the [] method on the params[:Jobs] object passing :clearance in as a parameter.
#German, tried to get answer for your question.
2.1.3 :025 > class AntiArray < Array
2.1.3 :026?> def [](ind)
2.1.3 :027?> self.fetch(-ind) + 1
2.1.3 :028?> end
2.1.3 :029?> end
=> :[]
2.1.3 :030 > y = AntiArray.new([1,2,3,4])
=> [1, 2, 3, 4]
2.1.3 :031 > y[1]
=> 5
2.1.3 :032 >
Hope this is what you are asking for. Given a try for you

Resources