3

Hopefully this is not a duplicate question, as I have spent weeks scouring StackOverflow for answers and have not found a solution to my problem.

I have a Ruby on Rails API (Ruby 1.9.3, Rails 4.0.0) and am using ActiveRecord to interact with our database. When a request is made to retrieve the currently scheduled banner, it works perfectly. When no banner is scheduled, however, a 500 response is experienced:

undefined method `id' for #\u003cBanner::ActiveRecord_Relation:0x0000000628fba8\u003

My understanding is that this is because an inherent "id" method is being attempted upon a "nil" which is the result from the database lookup when no qualifying record is found. How do I gracefully handle this scenario so that a 500 error is not encountered and so that I may return a more polite response to the requester?

Here is my controller:

class BannersController < ApplicationController
  load_and_authorize_resource

  respond_to :json

  # Look to see if any banners should be showing right now
  def current
    @banner = Banner.current
  end
end

Here is my model:

class Banner < ActiveRecord::Base
  self.table_name   = 'Banner'
  self.primary_key  = :BannerID

  alias_attribute :name,              :FriendlyName
  alias_attribute :banner_html,       :BannerHtml
  alias_attribute :banner_image,      :BannerImage
  alias_attribute :start_date,        :StartDate
  alias_attribute :end_date,          :EndDate
  alias_attribute :is_active,         :IsActive
  alias_attribute :is_removed,        :IsRemoved
  alias_attribute :start_date_time,   :StartDateTime
  alias_attribute :end_date_time,     :EndDateTime
  alias_attribute :hidden_text,       :HiddenText
  alias_attribute :hidden_background_color,       :HiddenBackgroundColor

  # This returns nil if no banner is scheduled, which then causes the view to return a 500 response because it tries to invoke an "id" method
  scope :current, -> { Banner.where("StartDateTime <= ? AND EndDateTime >= ? AND IsActive=1 AND IsRemoved=0 AND BannerType=1", Time.now.to_s(:db), Time.now.to_s(:db)).first }  
end

Note: I have tried using .find_by and also tried not using .first, but still cannot seem to find a resolution to this.

Here is my view:

json.extract! @banner, :id, :banner_html, :banner_image, :hidden_text, :hidden_background_color

json.request_id request.uuid

The database table "Banner" has a primary key of "BannerID".

Thanks to all who would take the time to look into this. I have spent untold hours reading and trying everything in order to remedy the situation, to no avail.

2
  • Try changing :id to :banner_id in json.extract! line Commented Jun 25, 2017 at 11:21
  • What is an ActiveRecord_Relation? Commented Jun 26, 2017 at 15:00

2 Answers 2

1

undefined method `id' for \u003cBanner::ActiveRecord_Relation:0x0000000628fba8\u003

The database table "Banner" has a primary key of "BannerID"

Then whey are using :id still!. Change

json.extract! @banner, :id, :banner_html, :banner_image, :hidden_text, :hidden_background_color

to

json.extract! @banner, :BannerID, :banner_html, :banner_image, :hidden_text, :hidden_background_color

Small Note:

By convention, the attributes should be in snake_case.

Sign up to request clarification or add additional context in comments.

3 Comments

Thank you so much for your help! I'm new to Ruby and your help is a lifesaver. When I made the change you suggested, I now get this response: undefined method 'BannerID' for #\u003cBanner::ActiveRecord_Relation
@RavingHermit What is the field name in the table? is it BannerID or banner_id?
The table field is BannerID in the database.
0

Why don't you just

if [email protected]?
  json.extract...
  ...
else
  json.null!
  (or whatever you want?)
end

3 Comments

I smell what you are cooking and I like it. Unfortunately, I still get the same error: undefined method 'id' for #\u003cBanner::ActiveRecord_Relation:0x00000007134640\u003e
This is my updated view: if [email protected]? json.extract! @banner, :id, :banner_html, :banner_image, :hidden_text, :hidden_background_color json.request_id request.uuid else json.null! end
Another way to handle it, that would actually be better maybe, would be to have a model.method that returns a "default" non available banner, and in the controller check: @banner = Banner.current like you have but followed by @banner = Banner.default unless @banner

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.