ruby-on-railsrubybadgemerit-gem

Merit gem - Display a specific badge and the users who obtained it


I would like to create a method badges#show such as it is done here in StackOverFlow in which the selected badge is displayed and the users who have obtained it. I have created a BadgesController in which I have the following:

  # Find badge
  before_action :set_badge, only: %i[show]

  # GET /badges/1
  def show; end

  private

  # Set badge
  def set_badge
    @badge = Merit::Badge.find(params[:badge_id])
  end

In merit.rb (I am only displaying the code for the first badge below):

# Use this hook to configure merit parameters
Merit.setup do |config|
  # Check rules on each request or in background
  # config.checks_on_each_request = true

  # Define ORM. Could be :active_record (default) and :mongoid
  # config.orm = :active_record

  # Add application observers to get notifications when reputation changes.
  # config.add_observer 'MyObserverClassName'

  # Define :user_model_name. This model will be used to grand badge if no
  # `:to` option is given. Default is 'User'.
  # config.user_model_name = 'User'

  # Define :current_user_method. Similar to previous option. It will be used
  # to retrieve :user_model_name object if no `:to` option is given. Default
  # is "current_#{user_model_name.downcase}".
  # config.current_user_method = 'current_user'
end

Merit::Badge.create!(
  id: 1,
  name: 'just-registered',
  description: 'New member',
  custom_fields: {
    icon_tag: 'user',
    category: 'user'
  }
)

# More badges [...]

However, when I try to display the badge name by doing <%= @badge.name %>, I get the following: undefined method 'name' for #<#<Class:0x000000001290cc18>:0x000000000c8c9d10>.

The params I am passing at the point I am calling the badges#show method is 1 (in the url: /badges/1).

The following lines throw the same error:

If I change @badge = Merit::Badge.find(params[:badge_id]) to @badge = Merit::Badge.find(:id) I get this: Could not find Merit::Badge with key "id".

When I try to debug my code, here is what happens with <%= debug @badge %> in the view (with @badge = Merit::Badge.find(params[:badge_id])):

#<#<Class:0x000000000da762c0>:0x000000000af48a80 @keys=[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49], @mapper=#<Ambry::Mapper:0x000000000af48f58 @klass=Merit::Badge(id, name, level, description, custom_fields), @adapter_name=:main, @indexes={}, @lock=#<Thread::Mutex:0x000000000af48d28>, @options={}, @hash={1=>{:id=>1, :name=>"just-registered", :level=>nil, :description=>"New member", :custom_fields=>{:icon_tag=>"user", :category=>"user"}} [...]

It displays a hash with all the badges I have in my initializer file merit.rb. I do not understand why the id parameter is not being passed by the controller.

<%= @badge.find(1).name %> in the view works fine however.

What have I done wrong?

Thank you in advance!


Solution

  • I finally managed to make it work!

    Here is my solution:

    In badges_controller.rb:

    class BadgesController < ApplicationController
    
      # GET /badges/1
      def show; end
    
      private
    
      # Set badge
      def set_badge
        @badge = Merit::Badge.find(params[:badge_id])
        @id = @badge.keys[params[:id].to_i]
        @badge = @badge.find(@id)
      end
    
    end
    

    Then in the view show.html.erb, it is possible to call the usual methods as per the documentation:

    <%= @badge.name %>
    <%= @badge.description %>
    <% @badge.users.each do |user| %>
      <%= user.full_name %>
      <%= (user.sash.badges_sashes[params[:id].to_i].created_at).to_formatted_s(:long) %>
    <% end %>
    

    For information, the path must be badge_path(badge.id - 1) to redirect to the correct badge (arrays start at 0).