ruby-on-railsdevisemerit-gem

Rails 4 / Devise / Merit gem : no target_obj found on Rule#applies?


I'm trying to implement a badge system in my Rails app using the Merit gem.

I want to give a badge to the 100 first users of my app. So I add this code to badge_rules.rb

grant_on 'registrations#create', badge: 'Pioneer', model_name: 'User', to: :itself do |user|
   user.id < 101
end

Since I'm using Devise (version 3.2.3), I followed this Howto and overdrived the registration controller like this :

class RegistrationsController < Devise::RegistrationsController
  def create
    @user = build_resource # Needed for Merit
    super
  end

  def update
    @user = resource # Needed for Merit
    super
  end
end

But the badge is'nt created. In the log, I can find these warnings :

[merit] no target_obj found on Rule#applies?

[merit] No object found, maybe you need a '@registration' variable in 'registrations_controller'?

I've put a binding.pry in the rule.rb file of the gem, and it's clear : the target_obj is not an User, it's nil.

The target_obj is supposed to be set by the to: option in badges_rules.rb. So I tried :itself, :user, and even nothing, but it don't solve my problem.

Of course I tried to add @registration = build_resource to my controller, it took away the warning but didn't solve the problem.

The behaviour of another badge is kind of wrong. It's suposed to be granted to anybody who registered succesfully. The working code is this one :

grant_on 'registrations#create', badge: 'Inscription', model_name: 'User'

But when I had to: :itself to it, like @TuteC advise me to in another question, it don't work.

I really don't understand the behaviour of the to: parameter.


Solution

  • The :to parameter can be a method name, which called over the target object (in this case, @registration) should retrieve the object to badge. If using it this way, when you put :user, then merit is internally running @registration.user to find who to badge, which is not what we want.

    :to can also be :itself, in that case it badges the target object (@registration in your case, which, if a User, should work for you).

    I believe you want to badge whoever is current_user, which is this option's default (:action_user), so you shouldn't need to define :to option.

    That said, for merit to badge, condition has to be true, and it can happen that there's no user to pass as a parameter to that rule. Try it without the parameter:

    grant_on 'registrations#create', badge: 'Pioneer' do
      User.count < 101
    end