mongoid-history: NoMethodError: undefined method `where' for HistoryTracker:Class

I am using mongoid-history(0.5.0) with an rails(5.0.0) and mongoid(github master branch). The changes are

#app/models/history_tracker.rb
class HistoryTracker
  include Mongoid::History::Trackable
end

#config/initializers/history_tracker.rb
Mongoid::History.tracker_class_name = :history_tracker

#app/models/user.rb
class User
  include Mongoid::Document
  include Mongoid::Timestamps
  include Mongoid::History::Trackable
  include Mongoid::Attributes::Dynamic

  ...
  field :name, type: String
  field :points, type: Integer, default: 0
  ...

  track_history on: [:name, :points], track_create: false, track_update: true, track_destroy: true
end

When I run ‘user.history_tracks’ in rails console, I get

2.3.0 :012 > user = User.last
 => #<User _id: 10de0dd7710542, created_at: 2016-09-13 15:10:07 UTC, updated_at: 2016-09-13 15:10:07 UTC, email: "prasad@gmail.com", encrypted_password: "$2a$10$ByExx918bnV6", remember_created_at: nil, sign_in_count: 1, current_sign_in_at: 2016-09-13 15:10:07 UTC, last_sign_in_at: 2016-09-13 15:10:07 UTC, current_sign_in_ip: "::1", last_sign_in_ip: "::1", github_handle: "prasad", active: true, name: "Prasad Surase", provider: "github", uid: "56", avatar_url: "https://avatars.githubusercontent.com/u/56?v=3", points: 0, version: nil, modifier_id: nil> 
2.3.0 :013 > user.version
 => nil 
2.3.0 :014 > user.modifier_id
 => nil 
2.3.0 :015 > user.history_trac
user.history_trackable_options  user.history_tracks             
2.3.0 :015 > user.history_tracks
NoMethodError: undefined method `where' for HistoryTracker:Class
    from /Users/prasad/.rvm/gems/ruby-2.3.0/gems/mongoid-history-0.5.0/lib/mongoid/history/trackable.rb:75:in `history_tracks'
    from (irb):15
    from /Users/prasad/.rvm/gems/ruby-2.3.0/gems/railties-4.2.5/lib/rails/commands/console.rb:110:in `start'
    from /Users/prasad/.rvm/gems/ruby-2.3.0/gems/railties-4.2.5/lib/rails/commands/console.rb:9:in `start'
    from /Users/prasad/.rvm/gems/ruby-2.3.0/gems/railties-4.2.5/lib/rails/commands/commands_tasks.rb:68:in `console'
    from /Users/prasad/.rvm/gems/ruby-2.3.0/gems/railties-4.2.5/lib/rails/commands/commands_tasks.rb:39:in `run_command!'
    from /Users/prasad/.rvm/gems/ruby-2.3.0/gems/railties-4.2.5/lib/rails/commands.rb:17:in `<top (required)>'
    from ./bin/rails:4:in `require'
    from ./bin/rails:4:in `<main>'

Am I missing something or is this a valid bug?

About this issue

  • Original URL
  • State: open
  • Created 8 years ago
  • Comments: 20 (1 by maintainers)

Commits related to this issue

Most upvoted comments

Not entirely sure if this is related, but I’ll just throw it out there.

I’ve had an issue with Rails 5.0.1, Mongoid 6.0.2 and Mongoid-History 0.6.0. The app acts as a standalone API and shares its database with a Rails 4 app. The Rails 5 app is read-only and I did not have a problem with it up until today when I opened a rails console and tried to update a record, which always returned false. Even without calling save or validate every record had errors and was invalid right from when loaded. When I inspected the errors I got

record.errors.messages
#=> :modifier=>["can't be blank"]

So, after a little research (with a short stop in this thread) I ended up reading the mongoid config specs and realised they are setting Mongoid.belongs_to_required_by_default = true by default, which is in compliance with the rails 5 active record default setting (changed from default = false to default = true), but screwed up everything when not saving a modifier.

Simply adding an initializer solved the problem:

# config/initializers/mongoid_belongs_to_required_by_default.rb

Mongoid.belongs_to_required_by_default = false

@dblock The issue basically is that ActiveRecord changed its policy towards relations with Rails 5. Before, when you defined a belongs_to relation, the foreign key was not required (could be null or not), now it is required by default unless stated otherwise.

Mongoid adopted that behavior, which breaks mongoid-history if you try to save a history without setting the modifier_id (belongs_to relation), because modifier_id will now be validated for presence by default - hence the :modifier => "cant be blank" error message.

It is not related to the original issue I think, but rather to the issue that prasadsurase ran into when creating a sample app:

2.3.0 :014 >   user = User.create(email: 'prasad@prasad.com', password: 'prasad123', password_confirmation: 'prasad123')
 => #<User _id: BSON::ObjectId('57d8e68b5f10de200053b8f6'), created_at: nil, email: "prasad@prasad.com", modifier_id: nil, name: nil, points: 0, updated_at: nil, version: nil> 
2.3.0 :015 > user.valid?
 => false 
2.3.0 :016 > user.errors
 => #<ActiveModel::Errors:0x007f9af9def670 @base=#<User _id: BSON::ObjectId('57d8e68b5f10de200053b8f6'), created_at: nil, email: "prasad@prasad.com", modifier_id: nil, name: nil, points: 0, updated_at: nil, version: nil>, @messages={:modifier=>["can't be blank"]}, @details={:modifier=>[{:error=>:blank}]}>

Issue for me was that creating through console the modifier_id needs to be passed manually or as some id from seed or as default value like, example:

  field :modifier_id, type: String, default: -> { self._id }

I have a solution to my question. Posting it for feedback, or in case anyone else has the problem …

In #139 @dblock mentions that you need to set the modifier explicitly. Seeing as though there is one model at the moment that I want to track changes in, I’ve added a merge to the strong params method which now looks like this:

def object_params
      params.require(:object).permit(:field1, :field2).merge(modifier: current_user)
end

This works, so I’ll keep it like this for now, unless anyone has a better implementation idea