1

Confusion over trying to get information from Rails Console

I have the following models: Article & Comment.

For Article, it's a has_many :comments

For Comment, it's belongs_to :article

Let's assume they're associated, and functional. They are by the way.

Here's the schema:

ActiveRecord::Schema.define(version: 20160312052519) do

  create_table "articles", force: :cascade do |t|
    t.string   "title"
    t.text     "text"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end

  create_table "comments", force: :cascade do |t|
    t.string   "commenter"
    t.text     "body"
    t.integer  "article_id"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end

  add_index "comments", ["article_id"], name: "index_comments_on_article_id"

end

These are the routes:

  resources :articles do 
    resources :comments 
  end

When I run commands like:

Article.first.comments

Comment.first.article

Comment.first.article.title

Comment.first.article.text

Comment.first.commenter

Comment.first.body

They all work.

But when I try to run the reverse on Articles like:

Article.first.comments.commenter

Article.first.comments.body

Article.all.comments

They don't work. Why not?

EDIT

This is what I get when I run Article.first.comments.commenter

Article.first.comments.commenter
  Article Load (23.0ms)  SELECT  "articles".* FROM "articles"  ORDER BY "articles"."id" ASC LIMIT 1
NoMethodError:   Comment Load (0.4ms)  SELECT "comments".* FROM "comments" WHERE "comments"."article_id" = ?  [["article_id", 1]]
undefined method `commenter' for #<Comment::ActiveRecord_Associations_CollectionProxy:0x007fa32b7e3d00>
    from /Users/aa/.rbenv/versions/2.1.4/lib/ruby/gems/2.1.0/gems/activerecord-4.2.5/lib/active_record/relation/delegation.rb:136:in `method_missing'
    from /Users/aa/.rbenv/versions/2.1.4/lib/ruby/gems/2.1.0/gems/activerecord-4.2.5/lib/active_record/relation/delegation.rb:99:in `method_missing'
    from (irb):127
    from /Users/aa/.rbenv/versions/2.1.4/lib/ruby/gems/2.1.0/gems/railties-4.2.5/lib/rails/commands/console.rb:110:in `start'
    from /Users/aa/.rbenv/versions/2.1.4/lib/ruby/gems/2.1.0/gems/railties-4.2.5/lib/rails/commands/console.rb:9:in `start'
    from /Users/aa/.rbenv/versions/2.1.4/lib/ruby/gems/2.1.0/gems/railties-4.2.5/lib/rails/commands/commands_tasks.rb:68:in `console'
    from /Users/aa/.rbenv/versions/2.1.4/lib/ruby/gems/2.1.0/gems/railties-4.2.5/lib/rails/commands/commands_tasks.rb:39:in `run_command!'
    from /Users/aa/.rbenv/versions/2.1.4/lib/ruby/gems/2.1.0/gems/railties-4.2.5/lib/rails/commands.rb:17:in `<top (required)>'
    from /Users/aa/.rbenv/versions/2.1.4/lib/ruby/gems/2.1.0/gems/activesupport-4.2.5/lib/active_support/dependencies.rb:274:in `require'
    from /Users/aa/.rbenv/versions/2.1.4/lib/ruby/gems/2.1.0/gems/activesupport-4.2.5/lib/active_support/dependencies.rb:274:in `block in require'
    from /Users/aa/.rbenv/versions/2.1.4/lib/ruby/gems/2.1.0/gems/activesupport-4.2.5/lib/active_support/dependencies.rb:240:in `load_dependency'
    from /Users/aa/.rbenv/versions/2.1.4/lib/ruby/gems/2.1.0/gems/activesupport-4.2.5/lib/active_support/dependencies.rb:274:in `require'
    from /Users/aa/dropbox/beginningRails/guideblogagain/bin/rails:9:in `<top (required)>'
    from /Users/aa/.rbenv/versions/2.1.4/lib/ruby/gems/2.1.0/gems/activesupport-4.2.5/lib/active_support/dependencies.rb:268:in `load'
    from /Users/aa/.rbenv/versions/2.1.4/lib/ruby/gems/2.1.0/gems/activesupport-4.2.5/lib/active_support/dependencies.rb:268:in `block in load'
    from /Users/aa/.rbenv/versions/2.1.4/lib/ruby/gems/2.1.0/gems/activesupport-4.2.5/lib/active_support/dependencies.rb:240:in `load_dependency'
    from /Users/aa/.rbenv/versions/2.1.4/lib/ruby/gems/2.1.0/gems/activesupport-4.2.5/lib/active_support/dependencies.rb:268:in `load'
    from /Users/aa/.rbenv/versions/2.1.4/lib/ruby/gems/2.1.0/gems/spring-1.6.4/lib/spring/commands/rails.rb:6:in `call'
    from /Users/aa/.rbenv/versions/2.1.4/lib/ruby/gems/2.1.0/gems/spring-1.6.4/lib/spring/command_wrapper.rb:38:in `call'
    from /Users/aa/.rbenv/versions/2.1.4/lib/ruby/gems/2.1.0/gems/spring-1.6.4/lib/spring/application.rb:185:in `block in serve'
    from /Users/aa/.rbenv/versions/2.1.4/lib/ruby/gems/2.1.0/gems/spring-1.6.4/lib/spring/application.rb:156:in `fork'
    from /Users/aa/.rbenv/versions/2.1.4/lib/ruby/gems/2.1.0/gems/spring-1.6.4/lib/spring/application.rb:156:in `serve'
    from /Users/aa/.rbenv/versions/2.1.4/lib/ruby/gems/2.1.0/gems/spring-1.6.4/lib/spring/application.rb:131:in `block in run'
    from /Users/aa/.rbenv/versions/2.1.4/lib/ruby/gems/2.1.0/gems/spring-1.6.4/lib/spring/application.rb:125:in `loop'
    from /Users/aa/.rbenv/versions/2.1.4/lib/ruby/gems/2.1.0/gems/spring-1.6.4/lib/spring/application.rb:125:in `run'
    from /Users/aa/.rbenv/versions/2.1.4/lib/ruby/gems/2.1.0/gems/spring-1.6.4/lib/spring/application/boot.rb:18:in `<top (required)>'
    from /Users/aa/.rbenv/versions/2.1.4/lib/ruby/2.1.0/rubygems/core_ext/kernel_require.rb:55:in `require'
    from /Users/aa/.rbenv/versions/2.1.4/lib/ruby/2.1.0/rubygems/core_ext/kernel_require.rb:55:in `require'
user273072545345
  • 1,536
  • 2
  • 27
  • 57

2 Answers2

1

Article.first.comments is an ActiveRecord_Associations_CollectionProxy object, which is similar to an array. If you want to get commenter for each comment you can use map

Article.first.comments.map(&:commenter)

Or you can get first comment's commenter:

Article.first.comments.first.commenter

Same thing with:

Article.first.comments.body # Won't work

Article.first.comments.map(&:body) # Returns an array (each comment's body)

Article.all.comments # Won't work

Article.all.map(&:comments) # Returns an array (each article's comments)
Max Filippov
  • 2,024
  • 18
  • 37
  • hey, thank you for your answer. Can I ask a follow-up question based on the answer that you've provided? `Article.first.comments.map(&:commenter)`, the `(&:commenter)` is a proc, correct? How is it calling the block of the commenter? Sorry if I didn't word the question correctly. – user273072545345 Mar 14 '16 at 23:27
  • @user27307254534534534543675765 yep, it is. Here you go: http://stackoverflow.com/a/1217114/999223 – Max Filippov Mar 14 '16 at 23:29
1

When you run your working example Article.first.comments, take a look at the actual return value. What do you see? The return is an array of objects, right? So say that Article.first has 10 Comments. When you run your query, ActiveRecord will return you an array of 10 Comment objects.

Now let's take a look at one of your non-working examples.

Say, Article.first.comments.commenter. Again we start with Article.first, which we know returns us the first Article object in our DB.

But the next step is to think about Article.first.comments.

We've already convinced ourselves that that's an array of Comment objects, right? And herein lies the problem -- commenter is an attribute on a single Comment object.

But you don't have a single Comment object -- you have an Array of Comment objects and commenter isn't defined on an Array.

The Article.first.comments.body issue is the same. Does that make sense?

One thing you could do, in your console, is the following:

Article.first.comments.each do |comment|  
  puts comment.commenter  
end 

And then you can get at all of your commenter/body values.

Using this line of thinking, I think you'll be able to convince yourself of the issue with Article.all.comments, but if not, feel free to comment and we can talk it out.

Here are the docs for Active Record relations, for reference. Cheers!

  • thank you for a thoughtful answer in asking me to think it out. I understand now that as `body` and `commenter` goes, they are single items that I was asking over an array which of course wouldn't work. But I do have one question about `Article.all.comments`. Why doesn't that work? I mean `Article.all` works, right? And `comments` is not a single property per se, so ... ? – user273072545345 Mar 14 '16 at 23:20
  • Think of `Article.all` as of array (although it's not). You are trying to call method `comments` on the collection, which knows nothing about its members: whether they have `comments` method or not. You need to call `comments` on *the members* of the collection, e.g. iterate through them and use `map`. – Max Filippov Mar 14 '16 at 23:38
  • @queserasera, i've upvoted your answer. thank you very much. – user273072545345 Mar 14 '16 at 23:54
  • @user27307254534534534543675765 Thanks! I'm glad you were able to make progress! I wasn't sure how much to throw at you, but maximf nailed it. Cheers :) – queserasera Mar 15 '16 at 16:11
  • @queserasera, no worries. =) – user273072545345 Mar 15 '16 at 17:32