0

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:

  • @badge = Merit::Badge.find_by_id(params[:badge_id])
  • @badge = Merit::Badge.find_by_id(params[:id])
  • @badge = Merit::Badge.find(params[:id])

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!

Gabriel Guérin
  • 430
  • 2
  • 13
  • 1
    Try this one: @badge = Merit::Badge.find(params[:id]) – nattfodd May 13 '20 at 15:50
  • @nattfodd I get this `Could not find Merit::Badge with key "1"`. I do have a badge with id=1. – Gabriel Guérin May 13 '20 at 19:02
  • Badges use ambry, so syntax might differ with ActiveRecord. See https://github.com/norman/ambry. You can use `find_by_id`: https://github.com/merit-gem/merit/blob/master/app/models/merit/badge.rb#L15 – TuteC May 15 '20 at 19:10
  • @TuteC I wrote the following lines: `@badge = Merit::Badge.find_by_id(params[:badge_id])` & `@badge = Merit::Badge.find_by_id(params[:id])` Both still throw the same error as previously mentioned. – Gabriel Guérin May 15 '20 at 20:54
  • @TuteC Writing the lines mentioned in my previous comments without `params` throw the same error. – Gabriel Guérin May 15 '20 at 21:08
  • Just to be clear, the error I get is this one `undefined method 'name' for #<#:0x000000000c8c9d10>` – Gabriel Guérin May 15 '20 at 21:30
  • Can you share your initializer, and what params is at the point where you call it? Might be strings vs integer issue, for instance. Also, can you query badges in the rails console like that? – TuteC May 19 '20 at 23:06
  • @TuteC I updated my post, adding my *initializer* (I only added the first badge which is the one I try all the time), the **params** I am calling (which is **1**), and the various other options I have tried following the suggestions in the comments. As to query badges in the rails console like I do in my controller, writing `Merit::Badge.find(1)` returns: `#"user", :category=>"user"}>`. I am not sure if this is what you were asking for but it does seem to work however. – Gabriel Guérin May 20 '20 at 09:27
  • @TuteC I have updated my post with some more information and other options I have tried. I hope it helps! – Gabriel Guérin May 20 '20 at 10:42
  • @TuteC Thank you for your help! I finally managed to find a solution. I was wondering if it was possible to use `friendly-id` with Merit? Thank you in advance. – Gabriel Guérin May 20 '20 at 11:27

1 Answers1

0

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).

Gabriel Guérin
  • 430
  • 2
  • 13