4
votes

I have the following mongoid model, with a scoped validation to prevent multiple votes on one bill. Each vote belongs to a user and a group:

class Vote
  include Mongoid::Document
  field :value, :type => Symbol # can be :aye, :nay, :abstain
  field :type, :type => Symbol  # TODO can delete?

  belongs_to :user
  belongs_to :polco_group

  embedded_in :bill
  validates_uniqueness_of :value, :scope => [:polco_group_id, :user_id, :type]

end

The user has the following method to add a vote to a bill:

  def vote_on(bill, value)    
    if my_groups = self.polco_groups # test to make sure the user is a member of a group
      my_groups.each do |g|
          # TODO see if already voted
          bill.votes.create(:value => value, :user_id => self.id, :polco_group_id => g.id, :type => g.type)
      end
    else
      raise "no polco_groups for this user" # #{self.full_name}"
    end
  end

and a Bill class which embeds many :votes. This is designed to allow a user to associate their vote with different groups ("Ruby Coders", "Women", etc.) and is working well, except the database currently allows a user to vote multiple times on one bill. How can I get the following to work?

u = User.last
b = Bill.last
u.vote_on(b,:nay)
u.vote_on(b,:nay) -> should return a validation error

1

1 Answers

2
votes

Most probably validators on Vote are not getting fired. You can confirm that by adding a validates function and outputting something or raising an exception in it.

class Vote
  validate :dummy_validator_to_confirmation

  def dummy_validator_to_confirmation
    raise "What the hell, it is being called, then why my validations are not working?"
  end
end

If after creating above validations User#vote_on doesn't raises exception, it confirms that callbacks are not fired for Vote via vote_on method. You need to change your code to fire callbacks on Vote. Probably changing it to resemble following would help:

def vote_on(bill, value)    
  if my_groups = self.polco_groups # test to make sure the user is a member of a group
    my_groups.each do |g|
        # TODO see if already voted
        vote = bill.votes.new(:value => value, :user_id => self.id, :polco_group_id => g.id, :type => g.type)
        vote.save
    end
  else
    raise "no polco_groups for this user" # #{self.full_name}"
  end
end

There is an open issue on mongoid github issue tracker to allow cascade callbacks to embedded documents. Right now callbacks are only fired on document on which persistence actions are taking place on.