Writing new embedded document in Mongoid fails mysteriously - ruby-on-rails

I'm trying to embed a new document in a previously existing document. When the object was created, the root document looked like this:
class MongoPoll
include Mongoid::Document
embeds_one :region_count, :as => :voteable, :class_name => 'VoteCount'
I've added a few new embedded documents of the same class:
embeds_one :browser_count, :as => :voteable, :class_name => 'VoteCount'
embeds_one :os_count, :as => :voteable, :class_name => 'VoteCount'
The VoteCount class looks like:
class VoteCount
include Mongoid::Document
embedded_in :voteable, :polymorphic => true
When I create new documents from scratch, I create the embedded documents in a before_create handler, and it works fine:
self.region_count = VoteCount.new
self.browser_count = VoteCount.new
self.os_count = VoteCount.new
However, for migrating my old documents, I try to do the same assignment (poll.os_count = VoteCount.new; poll.save) and it fails silently for os_count (but oddly not for browser_count). When I try saving using update_attribute or poll['os_count'] = VoteCount.new from rails console, I get stacktraces that look like the following:
BSON::InvalidDocument: Cannot serialize an object of class VoteCount into BSON.
from /Library/Ruby/Gems/1.8/gems/bson-1.4.0/lib/../lib/bson/bson_c.rb:24:in `serialize'
from /Library/Ruby/Gems/1.8/gems/bson-1.4.0/lib/../lib/bson/bson_c.rb:24:in `serialize'
from /Library/Ruby/Gems/1.8/gems/mongo-1.4.0/lib/../lib/mongo/collection.rb:426:in `update'
from /Library/Ruby/Gems/1.8/gems/mongoid-2.2.2/lib/mongoid/collections/master.rb:19:in `update'
from /Library/Ruby/Gems/1.8/gems/mongoid-2.2.2/lib/mongoid/collections/retry.rb:29:in `retry_on_connection_failure'
from /Library/Ruby/Gems/1.8/gems/mongoid-2.2.2/lib/mongoid/collections/master.rb:18:in `update'
from /Library/Ruby/Gems/1.8/gems/mongoid-2.2.2/lib/mongoid/collection.rb:149:in `update'
from /Library/Ruby/Gems/1.8/gems/mongoid-2.2.2/lib/mongoid/persistence/operations/update.rb:45:in `persist'
from /Library/Ruby/Gems/1.8/gems/mongoid-2.2.2/lib/mongoid/persistence/modification.rb:25:in `prepare'
from /Library/Ruby/Gems/1.8/gems/activesupport-3.0.9/lib/active_support/callbacks.rb:414:in `_run_update_callbacks'
from /Library/Ruby/Gems/1.8/gems/activesupport-3.0.9/lib/active_support/callbacks.rb:94:in `send'
from /Library/Ruby/Gems/1.8/gems/activesupport-3.0.9/lib/active_support/callbacks.rb:94:in `run_callbacks'
from /Library/Ruby/Gems/1.8/gems/mongoid-2.2.2/lib/mongoid/persistence/modification.rb:24:in `prepare'
from /Library/Ruby/Gems/1.8/gems/activesupport-3.0.9/lib/active_support/callbacks.rb:414:in `_run_save_callbacks'
from /Library/Ruby/Gems/1.8/gems/activesupport-3.0.9/lib/active_support/callbacks.rb:94:in `send'
from /Library/Ruby/Gems/1.8/gems/activesupport-3.0.9/lib/active_support/callbacks.rb:94:in `run_callbacks'
from /Library/Ruby/Gems/1.8/gems/mongoid-2.2.2/lib/mongoid/persistence/modification.rb:23:in `prepare'
from /Library/Ruby/Gems/1.8/gems/mongoid-2.2.2/lib/mongoid/persistence/operations/update.rb:43:in `persist'
from /Library/Ruby/Gems/1.8/gems/mongoid-2.2.2/lib/mongoid/persistence.rb:86:in `update'
from /Library/Ruby/Gems/1.8/gems/mongoid-2.2.2/lib/mongoid/persistence.rb:151:in `save'
from (irb):5
Any idea what might be wrong here?

Related

Detect file type and resize if image

I have model Attachment whitch supprted pdf's and images. How to detect if its image and only then resize it ? When it's paperclip everything Was simple. but now ? ;)
class Attachment < ActiveRecord::Base
has_attached_file :attachment,
styles: lambda { |a| a.instance.is_image? ? {:small => "x200>", :medium => "x300>", :large => "x400>"} : {:thumb => { :geometry => "100x100#", :format => 'jpg'}, :medium => { :geometry => "300x300#", :format => 'jpg'}}},
def is_image?
attachment.instance.attachment_content_type =~ %r(image)
end
end
How to make something like above with active storage ? I try like this:
class Attachment < ApplicationRecord
has_one_attached :file
validates :file, presence: true
def file_url
if ???? (is image?)
rails_blob_url(file.variant(resize: '1920x1920').processed)
else
rails_blob_url(file)
end
end
ActiveStorage has build in helpers for popular content-types like: image, video, audio etc. For image is image?:
if file.image?
rails_representation_url(file.variant(resize: '1920x1920').processed)
else
rails_blob_url(file)
end
Api docs: https://api.rubyonrails.org/classes/ActiveStorage/Blob.html#method-i-image-3F
audio?, image?, text?, video?
I have tried this and.. What it is "signed_id" ?
NoMethodError (undefined method `signed_id' for #<ActiveStorage::Variant:0x00007fb67a4325f0>):
activestorage (5.2.0) config/routes.rb:7:in `block (2 levels) in <main>'
actionpack (5.2.0) lib/action_dispatch/routing/route_set.rb:641:in `instance_exec'
actionpack (5.2.0) lib/action_dispatch/routing/route_set.rb:641:in `eval_block'
actionpack (5.2.0) lib/action_dispatch/routing/route_set.rb:630:in `call'
actionpack (5.2.0) lib/action_dispatch/routing/route_set.rb:164:in `block (2 levels) in add_url_helper'
app/models/attachment.rb:27:in `file_url'
app/serializers/api/v1/attachment_serializer.rb:7:in `file_url'

Active Admin Show Page for one model is not working

I am integrating Active Admin into a Ruby on Rails app. I registered all my models and already set up index, filter and show for all the models. Everything is working, but for one model the admin/show page is not running.
When calling the show page from the admin/index page, I get:
NoMethodError in Admin/safts#show
Showing /Users/xxxxxx/.rvm/gems/ruby-1.8.7-p374#xxxxxx/gems/activeadmin-0.6.0/app/views/active_admin/resource/show.html.arb where line #1 raised:
undefined method `empty?' for #<Keyword:0x105498800>
Extracted source (around line #1):
1: insert_tag renderer_for(:show)
Request
Parameters:
{"id"=>"9"}
The relative entry in my log file is:
Started GET "/admin/safts/9" for 127.0.0.1 at Sun Feb 25 14:48:04 +0100 2018
Processing by Admin::SaftsController#show as HTML
Parameters: {"id"=>"9"}
[1m[35mAdminUser Load (0.6ms)[0m SELECT `admin_users`.* FROM `admin_users` WHERE `admin_users`.`id` = 2 LIMIT 1
[1m[36mSaft Load (0.2ms)[0m [1mSELECT `safts`.* FROM `safts` WHERE `safts`.`id` = ? LIMIT 1[0m [["id", "9"]]
[1m[35mKeyword Load (0.3ms)[0m SELECT `keywords`.* FROM `keywords` WHERE `keywords`.`id` = 138 LIMIT 1
Rendered /Users/xxxxxx/.rvm/gems/ruby-1.8.7-p374#xxxxxx/gems/activeadmin-0.6.0/app/views/active_admin/resource/show.html.arb (3.1ms)
Completed 500 Internal Server Error in 10ms
ActionView::Template::Error (undefined method `empty?' for #<Keyword:0x1052a0890>):
1: insert_tag renderer_for(:show)
activemodel (3.2.5) lib/active_model/attribute_methods.rb:407:in `method_missing'
activerecord (3.2.5) lib/active_record/attribute_methods.rb:149:in `method_missing'
activeadmin (0.6.0) lib/active_admin/views/pages/show.rb:38:in `default_title'
activeadmin (0.6.0) lib/active_admin/views/pages/show.rb:14:in `title'
activeadmin (0.6.0) lib/active_admin/views/pages/base.rb:25:in `build_active_admin_head'
arbre (1.0.1) lib/arbre/context.rb:92:in `with_current_arbre_element'
arbre (1.0.1) lib/arbre/element/builder_methods.rb:49:in `within'
activeadmin (0.6.0) lib/active_admin/views/pages/base.rb:24:in `build_active_admin_head'
activeadmin (0.6.0) lib/active_admin/views/pages/base.rb:9:in `build'
arbre (1.0.1) lib/arbre/element/builder_methods.rb:30:in `build_tag'
arbre (1.0.1) lib/arbre/context.rb:92:in `with_current_arbre_element'
arbre (1.0.1) lib/arbre/element/builder_methods.rb:26:in `build_tag'
arbre (1.0.1) lib/arbre/element/builder_methods.rb:39:in `insert_tag'
activeadmin (0.6.0) app/views/active_admin/resource/show.html.arb:1:in `___sers__tephan__rvm_gems_ruby_______p____somesite_gems_activeadmin_______app_views_active_admin_resource_show_html_arb___1026777847_2195984600'
arbre (1.0.1) lib/arbre/context.rb:45:in `instance_eval'
arbre (1.0.1) lib/arbre/context.rb:45:in `initialize'
activeadmin (0.6.0) app/views/active_admin/resource/show.html.arb:1:in `new'
activeadmin (0.6.0) app/views/active_admin/resource/show.html.arb:1:in `___sers__tephan__rvm_gems_ruby_______p____somesite_gems_activeadmin_______app_views_active_admin_resource_show_html_arb___1026777847_2195984600'
actionpack (3.2.5) lib/action_view/template.rb:145:in `send'
actionpack (3.2.5) lib/action_view/template.rb:145:in `render'
activesupport (3.2.5) lib/active_support/notifications.rb:125:in `instrument'
.
.
.
script/rails:6:in `gem_original_require'
script/rails:6:in `require'
script/rails:6
Rendered /Users/xxxxxx/.rvm/gems/ruby-1.8.7-p374#xxxxxx/gems/actionpack-3.2.5/lib/action_dispatch/middleware/templates/rescues/_trace.erb (0.7ms)
Rendered /Users/xxxxxx/.rvm/gems/ruby-1.8.7-p374#xxxxxx/gems/actionpack-3.2.5/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb (0.6ms)
Rendered /Users/xxxxxx/.rvm/gems/ruby-1.8.7-p374#xxxxxx/gems/actionpack-3.2.5/lib/action_dispatch/middleware/templates/rescues/template_error.erb within rescues/layout (9.8ms)
The rails model is:
class Saft < ActiveRecord::Base
attr_accessible :colour, :cover_alt, :description, :number, :short, :title_id
# Associations
has_and_belongs_to_many :keywords, :join_table => "safts_keywords"
has_many :authors, :through => :texts
has_many :texts
belongs_to :title, :class_name => "Keyword", :foreign_key => "title_id"
has_one :cover
has_many :stamps
has_many :images
end
The ActiveAdmin resource is:
ActiveAdmin.register Saft do
index do
column "Issue", :number
column "Title", :title_id do |saft|
link_to saft.title.word.capitalize, saft_path(saft)
end
column :short
column :description
column :colour
column :cover_alt
default_actions
end
# Filter only by:
filter :title_id, :label => 'Title', :as => :select, :collection => Saft.all.map{|u| ["#{u.title.word.capitalize}", u.id]}
filter :short
form do |f|
f.inputs "Saft Details" do
f.input :number, :label => "Number of issue"
f.input :title_id, :label => 'Title', :as => :select, :collection => Keyword.all.map{|u| ["#{u.word.capitalize}", u.id]}
f.input :short
f.input :description
f.input :colour, :label => "Colour (in hex)"
f.input :cover_alt
end
f.actions
end
show do
panel "Saft Details" do
attributes_table_for saft do
row :id
row :number
row :title_id
row :short
row :description
row :colour
row :cover_alt
row :created_at
row :updated_at
end
end
active_admin_comments
end
end
Just for context: SAFT is a magazine, with texts, images, authors, etc. All the other resources are working well in Admin. Only the show page of SAFT is not working. What could it be?
Your log entry says Keyword does not respond to empty? in Pages::Show#default_title.
default_title calls display_name, have you overridden display_name_methods? In this case you can remove :title
In config/initializers/active_admin:
config.display_name_methods = [ :display_name,
:full_name,
:name,
:username,
:login,
:email,
:to_s ]
Perhaps better in this case you can also try setting the title explicitly, eg.
show title: :short do ...
I notice you are on very old versions of Rails and ActiveAdmin, I hope you will consider upgrading.
I was able to solve the problem, which is related to the associations.
The DisplayHelper Module of the gem has to be modified as follows:
module ActiveAdmin
module ViewHelpers
module DisplayHelper
# Attempts to call any known display name methods on the resource.
# See the setting in `application.rb` for the list of methods and their priority.
def display_name(resource)
resource.send display_name_method_for resource
end
# Looks up and caches the first available display name method.
def display_name_method_for(resource)
##display_name_methods_cache ||= {}
##display_name_methods_cache[resource.class] ||= begin
methods = active_admin_application.display_name_methods - association_methods_for(resource)
methods.detect{ |method| resource.respond_to? method }
end
end
# To prevent conflicts, we exclude any methods that happen to be associations.
def association_methods_for(resource)
return [] unless resource.class.respond_to? :reflect_on_all_associations
resource.class.reflect_on_all_associations.map(&:name)
end
# Return a pretty string for any object
# Date Time are formatted via #localize with :format => :long
# ActiveRecord objects are formatted via #auto_link
# We attempt to #display_name of any other objects
def pretty_format(object)
case object
when String
object
when Arbre::Element
object
when Date, Time
localize(object, :format => :long)
when ActiveRecord::Base
auto_link(object)
else
display_name(object)
end
end
end
end
end
This is because in the SAFT model there is an association with the name title, which goes into conflict with the display_name_method.

Why does `has_many` association generate an error when using the `:dependent => :restrict`option?

Ruby 2.2 , Rails 3.21
I got the following error when I try to destroy my object.
This happen with any object whose model has an association with :dependent => :restrict option
This error is strange because it suggests a NIL object, though when I log the class and Id of the related object just before the error, it shows the expected class with correct ID.
NoMethodError in Projects::ProjClefsRepartitionController#destroy
undefined method `name' for nil:NilClass
app/controllers/projects/proj_clefs_repartition_controller.rb:322:in
block in destroy
app/controllers/projects/proj_clefs_repartition_controller.rb:315:in destroy
This is the related code of the ProjClefsRepartitionController controller :
294# def destroy
295#
296# messages = {}
297#
298# # Create the #proj_clef_repartition objet
299# unless creer_instance_objet_et_render_parent_si_impossible(ProjClefRepartition, params[:id], params[:proj_sous_projet_id], [{:proj_sous_projet => [:proj_charges, {:proj_projet => {:proj_mesure => :proj_paquet_mesures}}]}]) then
300#
301# enregistrement_ok = false
302#
303# #objet_de_l_erreur = #proj_clef_repartition
304# #proj_sous_projet = #proj_clef_repartition.proj_sous_projet
305# #proj_projet = #proj_sous_projet.proj_projet
306# #proj_mesure = #proj_projet.proj_mesure
307# #proj_paquet_mesures = #proj_mesure.proj_paquet_mesures
308# #hist_version_sous_projet = HistVersionSousProjet.where(:proj_sous_projet_id => #proj_sous_projet.id).order{version.desc}.limit(1)[0]
309#
310# #proj_clefs_repartition = #proj_sous_projet.proj_clefs_repartition
311# #proj_charges = #proj_sous_projet.proj_charges
312# #total_charges = BigDecimal.new('0', 18)
313#
314# # =================== DEBUT DE LA TRANSACTION ===================
315# ProjClefRepartition.transaction do
316#
317#
318# if sauver_version(#proj_clef_repartition, messages, nil, 3, nil, true) then
319#
320# logger.debug "#{#proj_clef_repartition.blank?}"
321# logger.debug "#{#proj_clef_repartition.class} (#{#proj_clef_repartition.id})"
322# if #proj_clef_repartition.destroy then
323# ajouter_message(t('activerecord.successful.messages.deleted', :model => ProjClefRepartition.model_name.human), :success, messages)
324# enregistrement_ok = true
325# else
326# ajouter_message(t('activerecord.warning.messages.deleted', :model => ProjClefRepartition.model_name.human), :alert, messages)
327# end # proj_clef_repartition.destroy
328#
329# end # sauver_version(#proj_clef_repartition, messages, nil, 3, nil, true)
330#
331#
332# raise ActiveRecord::Rollback unless enregistrement_ok
333#
334# end # ProjClefRepartition.transaction
335# # =================== FIN DE LA TRANSACTION ===================
336#
337#
338# afficher_maintenant(messages)
339#
340# render 'projects/proj_sous_projets/show'
341#
342# end # creer_instance_objet_et_render_parent_si_impossible(ProjClefRepartition, params[:id], params[:proj_sous_projet_id])
343#
344#
345# rescue ActiveRecord::StatementInvalid => exception
346#
347#
348#
349#
350#
351# #hist_sous_projet = #hist_version_sous_projet.hist_sous_projet
352# ajouter_message(t('activerecord.warning.messages.invalid_db_statement'), :error, messages)
353# ajouter_erreur_concernant_exception_statement_invalid(exception, #objet_de_l_erreur)
354# afficher_maintenant(messages)
355# render 'projects/proj_sous_projets/show'
356#
357#
358# rescue ActiveRecord::DeleteRestrictionError => exception
359#
360#
361# #hist_sous_projet = #hist_version_sous_projet.hist_sous_projet
362#
363# ajouter_message(t('activerecord.warning.messages.delete_restriction', :model => ProjClefRepartition.model_name.human), :error, messages)
364# afficher_maintenant(messages)
365# render 'projects/proj_sous_projets/show'
366#
367# end # destroy
Following is an extract of the log that is related to the error.
You can see that the object is not blank and has a class with a valid ID.
It shows false for #proj_clef_repartition.blank? logging.
It shows ProjClefRepartition (96) for #proj_clef_repartition.class and #proj_clef_repartition.id
QUITTING ||| historisation_nouvelle_version_avec_origine
(pub_modification_id = 2) ||| ===>
output_hash[:id_hist_origine_modification] = 1202 (0.4ms) SELECT
COUNT(*) FROM "proj_charges" WHERE
"proj_charges"."proj_clef_repartition_id" = 96
false
ProjClefRepartition (96)
(0.4ms) ROLLBACK
Completed 500 Internal Server Error in 298.9ms
NoMethodError (undefined method name' for nil:NilClass):
app/controllers/projects/proj_clefs_repartition_controller.rb:322:in
block in destroy'
app/controllers/projects/proj_clefs_repartition_controller.rb:315:in
`destroy'
Rendered
/home/douglas/.rvm/gems/ruby-2.2.0#rail3/gems/actionpack-3.2.21/lib/action_dispatch/middleware/templates/rescues/_trace.erb
(2.4ms) Rendered
/home/douglas/.rvm/gems/ruby-2.2.0#rail3/gems/actionpack-3.2.21/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb
(1.9ms) Rendered
/home/douglas/.rvm/gems/ruby-2.2.0#rail3/gems/actionpack-3.2.21/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb
within rescues/layout (21.8ms)
It does not make sense. I checked the full trace, and noticed that the "Nil" object error which happened in active_record has_many association.
Here it is the full trace :
NoMethodError in Projects::ProjClefsRepartitionController#destroy
undefined method `name' for nil:NilClass Rails.root: /var/www/odpf
Application Trace | Framework Trace | Full Trace
activerecord (3.2.21)
lib/active_record/associations/has_many_association.rb:58:in
`cached_counter_attribute_name'
activerecord (3.2.21)
lib/active_record/associations/has_many_association.rb:54:in
`has_cached_counter?'
activerecord (3.2.21)
lib/active_record/associations/has_many_association.rb:37:in
`count_records'
activerecord (3.2.21)
lib/active_record/associations/collection_association.rb:261:in `size'
activerecord (3.2.21)
lib/active_record/associations/collection_association.rb:280:in
`empty?'
activerecord (3.2.21)
lib/active_record/associations/collection_proxy.rb:46:in `empty?'
activerecord (3.2.21)
lib/active_record/associations/builder/has_many.rb:63:in `block in
define_restrict_dependency_method'
activesupport (3.2.21) lib/active_support/callbacks.rb:418:in
`_run__1417810521555210605__destroy__1154072583585286936__callbacks'
activesupport (3.2.21) lib/active_support/callbacks.rb:405:in
`__run_callback'
activesupport (3.2.21) lib/active_support/callbacks.rb:385:in
`_run_destroy_callbacks'
activesupport (3.2.21) lib/active_support/callbacks.rb:81:in
`run_callbacks'
activerecord (3.2.21) lib/active_record/callbacks.rb:254:in `destroy'
activerecord (3.2.21) lib/active_record/transactions.rb:254:in `block
in destroy'
activerecord (3.2.21) lib/active_record/transactions.rb:313:in `block
in with_transaction_returning_status'
activerecord (3.2.21)
lib/active_record/connection_adapters/abstract/database_statements.rb:192:in
`transaction'
activerecord (3.2.21) lib/active_record/transactions.rb:208:in
`transaction'
activerecord (3.2.21) lib/active_record/transactions.rb:311:in
`with_transaction_returning_status'
activerecord (3.2.21) lib/active_record/transactions.rb:254:in
`destroy'
app/controllers/projects/proj_clefs_repartition_controller.rb:322:in
`block in destroy'
activerecord (3.2.21)
lib/active_record/connection_adapters/abstract/database_statements.rb:192:in
`transaction'
activerecord (3.2.21) lib/active_record/transactions.rb:208:in
`transaction'
app/controllers/projects/proj_clefs_repartition_controller.rb:315:in
`destroy'
So I checked my model ProjClefRepartition.
I made a successful test without error when I removed the , :dependent => :restrict part of the two line :
has_many :proj_contributions, :dependent => :restrict
has_many :proj_charges, :dependent => :restrict
require Rails.root.to_s + '/lib/opf_modules/opf_outils_models.rb'
class ProjClefRepartition < ActiveRecord::Base
include OutilsModels
# Renforcement de la sécurité avec declarative_authorization Gem
using_access_control
# Modifier les attributs contenant des string vides en des nil
before_validation :blank_string_attributes_to_nil
attr_accessible :code, :designation, :proj_sous_projet_id, :motivation, :pub_modification_id
validates :code, :designation, :proj_sous_projet_id, :pub_modification_id, :admin_utilisateur_id, :presence => true
attr_accessor :montant_contributions_total
validates :code, :length => { :in => 2..19 }, :uniqueness => { :case_sensitive => false }
validates :designation, :length => { :in => 2..60 }
validates :motivation, :length => { :in => 5..600 }, :allow_blank => true
validate :clef_repartition_exclusive_a_un_unique_sous_projet
belongs_to :proj_sous_projet
belongs_to :pub_modification
belongs_to :admin_utilisateur
has_many :proj_contributions, :dependent => :restrict
has_many :proj_charges, :dependent => :restrict
has_many :hist_versions_clefs_repartition, :class_name => HistVersionClefRepartition
# Méthode utilisée par la collection_select box
def texte_pour_collection_select
# Groupé les attributs afin d'améliorer la compréhension de l'utilisateur lors du choix par la select box
self.code + ' - ' + self.designation
end
# -------------------------------------------------------------
# Validations speciale
# -------------------------------------------------------------
private
def clef_repartition_exclusive_a_un_unique_sous_projet
# Lors de la création d'une nouvelle clé de répartition, l'ID est nil, et il n'y a aucun risque que la clef soit déjà utilisée par une charge
unless id.nil? then
# Trouver toutes les charges utilisant cette clé de répartition
proj_charges = ProjCharge.where(:proj_clef_repartition_id => id)
proj_charges.each do |c|
if c.proj_sous_projet_id != proj_sous_projet_id then
errors.add(:proj_sous_projet_id, I18n.t('activemodel.warning.messages.reaffectation_impossible', :modele_enfant => I18n.t('projects.proj_charges.model'), :modele_parent => I18n.t('projects.proj_sous_projets.model'), :modele => I18n.t('projects.proj_clefs_repartition.model')))
break
end # c.proj_sous_projet_id != proj_sous_projet_id
end # proj_charges.each
end # id.nil?
end # clef_repartition_exclusive_a_un_unique_sous_projet
end
So I'm really wondering if this could be a bug in Ruby on Rails version 3.21.
Any help is more than welcome.
=== EDIT ===
The two other associated models (proj_charge and proj_contribution) do have the following line :
belongs_to :proj_clef_repartition

Can't do geo query on embedded document using Mongoid and Geocoder

(Ruby 1.9.3, MongoDB 2.0.4, Rails 3.2, Mongoid 2.4, Geocoder 1.1.1)
I have the following models:
class Company
include Mongoid::Document
embeds_one :office
index [[ "office.coordinates", Mongo::GEO2D ]]
end
class Office
include Mongoid::Document
include Geocoder::Model::Mongoid
geocoded_by :address
field :city, :type => String
field :state, :type => String
field :coordinates, :type => Array
embedded_in :company
after_validation :geocode
def address
"#{city}, #{state}"
end
end
I do this in the console:
> c = Company.new
=> #<Company _id: 4f885aa56d20f03898000003, _type: nil>
> c.office = Office.new(:city => "San Francisco", :state => "CA")
=> #<Office _id: 4f885ab66d20f03898000004, _type: nil, city: "San Francisco", state: "CA", coordinates: nil>
> c.save
=> true
So far so good. But then I try to retrieve the company by doing a geoquery on its embedded document (office):
> Company.where(:office.near => Company.first.office.to_coordinates).first
Mongo::OperationFailure: can't find special index: 2d for: { office: { $near: [ -122.4194155, 37.7749295 ] } }
from /Users/raphael/.rvm/gems/ruby-1.9.3-p125/gems/mongo-1.6.2/lib/mongo/cursor.rb:144:in `next'
from /Users/raphael/.rvm/gems/ruby-1.9.3-p125/gems/mongo-1.6.2/lib/mongo/collection.rb:288:in `find_one'
from /Users/raphael/.rvm/gems/ruby-1.9.3-p125/gems/mongoid-2.4.8/lib/mongoid/collections/master.rb:25:in `block in find_one'
from /Users/raphael/.rvm/gems/ruby-1.9.3-p125/gems/mongoid-2.4.8/lib/mongoid/collections/retry.rb:29:in `retry_on_connection_failure'
from /Users/raphael/.rvm/gems/ruby-1.9.3-p125/gems/mongoid-2.4.8/lib/mongoid/collections/master.rb:24:in `find_one'
from /Users/raphael/.rvm/gems/ruby-1.9.3-p125/gems/mongoid-2.4.8/lib/mongoid/collection.rb:60:in `find_one'
from /Users/raphael/.rvm/gems/ruby-1.9.3-p125/gems/mongoid-2.4.8/lib/mongoid/contexts/mongo.rb:203:in `first'
from /Users/raphael/.rvm/gems/ruby-1.9.3-p125/gems/mongoid-2.4.8/lib/mongoid/criteria.rb:45:in `first'
from (irb):2
from /Users/raphael/.rvm/gems/ruby-1.9.3-p125/gems/railties-3.2.3/lib/rails/commands/console.rb:47:in `start'
from /Users/raphael/.rvm/gems/ruby-1.9.3-p125/gems/railties-3.2.3/lib/rails/commands/console.rb:8:in `start'
from /Users/raphael/.rvm/gems/ruby-1.9.3-p125/gems/railties-3.2.3/lib/rails/commands.rb:41:in `<top (required)>'
from script/rails:6:in `require'
from script/rails:6:in `<main>'
What am I doing wrong? I've run rake db:mongoid:create_indexes.
You need to run the query against the embedded field:
Company.where(:'office.coordinates'.near => Company.first.office.to_coordinates).first
If you want to leverage the near scope created by the geocoder gem under Office, you can do something like the following:
# in Company.rb
self.near(office, radius = 20, conditions = {})
self.where(conditions).tap do |criteria|
near_criteria = Office.scopes[:near].conditions.call(office, radius)
criteria.selector[:'office.coordinates'] = near_criteria.selector[:coordinates]
end
end
This creates Company#near which takes an Office object. It will inject the query created by the Office#near scope into a query for a company.

Rails 3: NameError with association

I am brand new to Ruby, and have just now touched upon associations. Here are my models:
class Subject < ActiveRecord::Base
has_many :pages
scope :visible, where(:visible => true)
scope :invisible, where(:visible => false)
scope :search, lambda {|query| where(["name LIKE ?", "%#{query}%"])}
end
class Page < ActiveRecord::Base
belongs_to :subject
has_many :sections
has_and_belongs_to_many :editors, :class_name => "AdminUser"
end
My tutorial (psh.. what does it know) told me to type "subject.pages", after finding the first subject, like this:
Loading development environment (Rails 3.0.10)
irb(main):001:0> Subject.find(1)
=> #<Subject id: 1, name: "Initial Subject", position: 1, visible: true, created
_at: "2010-09-29 20:51:09", updated_at: "2010-09-29 21:07:42">
irb(main):002:0> subject.pages
NameError: undefined local variable or method `subject' for main:Object
from (irb):2
from C:/Ruby192/lib/ruby/gems/1.9.1/gems/railties-3.0.10/lib/rails/comma
nds/console.rb:44:in `start'
from C:/Ruby192/lib/ruby/gems/1.9.1/gems/railties-3.0.10/lib/rails/comma
nds/console.rb:8:in `start'
from C:/Ruby192/lib/ruby/gems/1.9.1/gems/railties-3.0.10/lib/rails/comma
nds.rb:23:in `<top (required)>'
from script/rails:6:in `require'
from script/rails:6:in `<main>'
irb(main):003:0>
According to the tutorial, it should have came back with an empty array. I have searched Google, this site, Yahoo Answers, everywhere for a possible explanation. Everything just seems to be correct to me. Can anyone help?
You need to store the result of Subject.find(1) into a variable before using it, just like you would with any language:
subject = Subject.find(1)
Then you can do subject.pages. Otherwise subject doesn't refer to anything.
Alternatively, you can use _ to refer to the return value of the last expression. So you could type Subject.find(1) and then _.pages.
If you're new to Ruby, though, I recommend going through this and perhaps this tutorial, and if you're feeling brave, this guide.

Resources