Search code examples
ruby-on-railsrubyruby-on-rails-5draper

Undefined method exists? for Draper::CollectionDecorator


I am trying to implement the Draper gem for my Rails project and having trouble getting it to work. I'm getting the error message:

undefined method `exists?' for #Draper::CollectionDecorator:0x000055b625da7a10>

The error seems to be coming up from a partial I'm rendering on my index view. The partial is calling "@accounts.exists?" which is where the error is happening. If I remove the call to the partial my decorator works fine. I have a feeling I need to use a delegate command for this but I'm not sure. I am fairly new to Rails and just starting to explore some of the helpful gems out there. I'm hoping someone could take a look at my code and point me in the right direction to get past this error. Thanks! :)


Model: Account.rb

# An account which will store many transactions and belongs to one user
class Account < ApplicationRecord
  belongs_to :user
  has_many :transactions, dependent: :destroy

  validates :name, presence: true, length: { maximum: 50, minimum: 2 }
  validates :starting_balance, presence: true
  validates :last_four, length: { maximum: 4 }

  # validates_associated :transactions

  after_create :create_initial_transaction

  def create_initial_transaction
    update(current_balance: 0.00)
    # rubocop:disable Metrics/LineLength
    Transaction.create(trx_type: 'credit', trx_date: Time.current, account_id: id, description: 'Starting Balance', amount: starting_balance)
    # rubocop:enable Metrics/LineLength
  end
end

Controller: accounts_controller.rb

class AccountsController < ApplicationController
  before_action :authenticate_user!
  before_action :set_account, only: %i[show edit update destroy activate deactivate]

  # GET /accounts
  # GET /accounts.json
  def index
    @accounts = current_user.accounts.where(active: true).order('created_at ASC')
    @accounts = @accounts.decorate
  end

  def inactive
    @accounts = current_user.accounts.where(active: false).order('created_at ASC')
  end

  private

  # Use callbacks to share common setup or constraints between actions.
  def set_account
    @account = current_user.accounts.find(params[:id])
  end

  # Never trust parameters from the scary internet, only allow the white list through.
  def account_params
    params.require(:account).permit(:name, :starting_balance, :current_balance, :last_four, :active, :user_id)
  end
end

Decorator: account_decorator.rb

class AccountDecorator < Draper::Decorator
  decorates_finders
  decorates_association :user
  delegate_all

  def last_four_formatted
    last_four.present? ? ' ( ... ' + last_four.to_s + ')' : nil
  end
end

View: accounts/index.html.erb

<%= render partial: "shared/pagetitle", locals: { page_model: "account", description: "Accounts" } %>

<!-- Render the message if no accounts exist -->
<%= render partial: "accounts/noaccounts", locals: { description: "It looks like you don't have any accounts added. To add an account, click the add account button at the top of the page :)" } %>

<div class="row" id="accounts">
  <%= render partial: "accounts/account", collection: @accounts %>
</div>

View Partial: accounts/_noaccounts.html.erb

<% if !@accounts.exists? then %>
  <div class="row">
    <div class="col s12 m8 offset-m2">
      <div class="card ob-card-gradient ob-account-card">
        <div class="card-content ob-text-primary">
          <span class="card-title">Welcome to mysite!</span>
          <div class="row">
            <br />
            <div class="col s1"><i class="material-icons valign-wrapper">account_balance</i></div>
            <div class="col s11">
            <%= description %></div>
          </div>
        </div>
      </div>
    </div>
  </div>
<% end %>

Solution

  • I am not familiar with the draper gem, but you are attempting to call exists? on what looks like a collection of objects, not on an ActiveRecord object. And since exists? is defined in ActiveRecord, you're not going to be able to do that.

    You can probably safely change this line:

    <% if !@accounts.exists? then %>
    

    to:

    <% if @accounts.empty? then %>
    

    The .empty? method is defined in multiple places, but the gist of it is if an object like a collection is empty then it will return true.