Topic: How to retrieve single record/model from an ActiveRecord::Relation

Hi there...RoR (3.2.x) noob here.  I'm coming from the world of Java/J2EE.  I'm having a difficult time wrapping my head around ActiveRecord's approach to ORM and their 'relations' model.  I've read several guides on the subject and have searched the web for my particular hiccup.

I have a DIY (do-it-yourself) application that I'm building.  An article (DIY) has several steps, and each step can have more than one image.  I have the following AR model definitions. 

NOTE: I omitted everything but the relationship definitions because I don't think the attribute and validations are relavent to my question.

class Diy < ActiveRecord::Base
  has_many :steps
end

class Step < ActiveRecord::Base
  belongs_to :diy
  has_many :step_images
end

class StepImage < ActiveRecord::Base
  belongs_to :step 
end

I need the ability to get an image by some sequence number defined in StepImage, not by an iterator (I will use the iterator later).  Here is my problem.  Say I already acquired the steps from the diy via the usual method - the each method.

<% @diy.steps.each do |step| %>
  ...

Next, I want to get a single step_image by calling the first method of ActiveRecord class like so.  I know earlier I said I want to use a sequence number.  But for the sake of this question the .first method services the same point that I'm trying to get across.

<% images = step.step_images.first %>

When I try to call one of the StepImage methods, say 'url', I get the following error:  undefined method 'url' for nil:NilClass

<%= images.url %>

But, if I inspect the record (a.k.a model) I see that the object is not null, and I see all of its data

<%= images.inspect %>

I've been banging my head against the wall now for 2-3 days.  This should not be as difficult as it has been.  I know this is most likely user error on my part but nothing is standing out. 

I have even tried converting the result set to an array.  And still the same error

step.step_images.to_a[0].url

Somebody please help.  I'm almost getting bald from all the hair I ripped out of my head.

Thanks in advance..

Last edited by EpikNinja (2012-07-08 22:28:32)

Re: How to retrieve single record/model from an ActiveRecord::Relation

The call to

<%= images.url %>

supposes that you have 'url' method or attribute in StemImage model or StepImages table. That's why the error message you points it out clearly:

undefined method 'url' for nil:NilClass

That is the first thing to check out.

Second point - when you call

<% @diy.steps.each do |step| %>
...#some code

you are already have a Step object in your loop. When calling

<% images = step.step_images.first %>

you get the first StepImage object from the array you got. So it would be more 'clear' and logic to name the variable as 'image' and not 'images'.
Third point, of course you object StepImage is  also nil as the message tells. Why? May be you you have no step images associated to the Step object. Try to check it out if step_id is not nil on the StepImage object you get.
Post some more traces what you get when calling 'inspect' on Step or StepImage object.

Re: How to retrieve single record/model from an ActiveRecord::Relation

Thanks for your reply.  Responses to your answers are as follows...

1.  My StepImage model has a 'url' attribute.  I left that out of my model definitions (up top) because I didn't think it was relevant and I wanted to focus on the relations.  But perhaps I should list them so it's more clear.


2.  I'm aware that I have a Step object in each iteration of my loop.  And I'm also aware that step.step_images.first gets the first StepImage associated with the Step.  I have validated that by calling .class.name

step.step_images.first.class.name

But you are right about the variable name.  It should be singular, not plural.  That was a typo when writing this post.  In my code, it is correct.


3.  My StepImage is not null.  As stated on my first post, I see my data when I inspect the object.

<%= image.inspect %>

It's when I go to access an attribute, I get a null pointer.

After reading a bunch of documentation on the subject, I feel like I am adhering to the framework and API.  Could this be a bug in Rails?  I am using 3.2.

Re: How to retrieve single record/model from an ActiveRecord::Relation

I found a solution.  It's not pretty but it'll due for now.  With a little help from someone on LinkedIn, I discovered that using the .try method on my model while attempting to access an attribute, I'm able to retrieve the value without the null pointer exception.

Example:

<% @diy.steps.each do |step| %>
  <% image = step.step_images.all[n]%>  # where 'n' is some index
  <%= image.try(:url) %>
  ...
<% end %>

It's not clear to me as why I need to use the .try method.  I mean, I know what the method is for.  It's a convenience method for checking nil values and allowing the page to render without exception.  But it's obvious that my model is not null and it has data.  So why am I only able to access its attributes with the .try method?

Honestly, I think this could be a bug in Rails.